简介
本文主要基于Android 7.0 介绍IP LOST_PROVISIONING 的情况的处理逻辑;
通过Android-IpReachabilityMonitor文章可知对于处于IpWatchlist中neighbor网络,Android 会定期持续地去Probe相应的neighbor状态,如果得不到任何响应response, 则可能将该neighbor的状态置为NUD_FAILED,进一步发出neighbor 配置丢失的消息LOST_PROVISIONING。
IpReachabilityMonitor
1、声明一个IpReachabilityMonitor Callback接口:
public interface Callback {
// This callback function must execute as quickly as possible as it is
// run on the same thread that listens to kernel neighbor updates.
// TODO: refactor to something like notifyProvisioningLost(String msg).
public void notifyLost(InetAddress ip, String logMsg);
}
2、IpReachabilityMonitor Callback接口调用
//在IpReachabilityMonitor构造函数中初始化
public IpReachabilityMonitor(Context context, String ifName, Callback callback,
AvoidBadWifiTracker tracker) throws IllegalArgumentException {
....
mCallback = callback;
....
}
//在IpReachiabilityMonitor的handleNeighborLost中,当neighbor的配置为LOST_PROVISIONING时调用回调函数
private void handleNeighborLost(String msg) {
......
if (delta == ProvisioningChange.LOST_PROVISIONING) {
if (mCallback != null) {
// TODO: remove |ip| when the callback signature no longer has an InetAddress argument.
mCallback.notifyLost(ip, logMsg);
}
}
......
}
3、IpReachabilityMonitor Callback接口的实现
IpReachabilityMonitor类的Callback Interface的实现是在IpManager类中。
在IpManager的RunningState状态的enter函数中,在启动Ipv6 和 Ipv4后,就会创建一个IpReachabilityMonitor的实例(在IpReachabilityMonitor的构造函数中就会启懂NetlinkSocketObserver子线程,用于接收Kernel 消息并解析,详见Android-IpReachabilityMonitor文章),同时对IpReachabilityMonitor的Callback进行赋值。
class RunningState extends State {
@Override
public void enter() {
.......
//启动IPv6
if (mConfiguration.mEnableIPv6) {
startIPv6();
}
//启动IPv4
if (mConfiguration.mEnableIPv4) {
if (!startIPv4()) {
transitionTo(mStoppingState);
return;
}
}
//使能IpReachabilityMonitor机制功能
if (mConfiguration.mUsingIpReachabilityMonitor) {
try {
mIpReachabilityMonitor = new IpReachabilityMonitor(
mContext,mInterfaceName,
new IpReachabilityMonitor.Callback() {
@Override
public void notifyLost(InetAddress ip, String logMsg) {
//回调IpManager类中mCallback对象
mCallback.onReachabilityLost(logMsg);
}
},
mAvoidBadWifiTracker);
} catch (IllegalArgumentException e) {
Log.e(mTag, "star IRM fail: " + e);
transitionTo(mStoppingState);
}
}
}
上面的分析可知IpReachabilityMonitor Callback接口的notifyLost(InetAddress ip, String logMsg) 调用IpManager Callback类的onReachabilityLost(logMsg)。
下面分析IpManager Callback类。
IpManager
1、IpManager Callback类的声明和初始化
public IpManager(Context context, String ifName, Callback callback,
INetworkManagementService nwService) throws IllegalArgumentException {
.....
mCallback = callback;
....
}
/** Callbacks for handling IpManager events.*/
public static class Callback {
......
// Called when the internal IpReachabilityMonitor (if enabled) hasdetected the loss of a critical number of required neighbors.
//当内部IpReachabilityMonitor(如果使能了)已经检测到需要的邻居neighbor网络达到一个临界数量丢失时,就会调用。
public void onReachabilityLost(String logMsg) {}
......
}
2、IpManager 子类Callback类的实现(主要针对onReachabilityLost 函数)
IpManager 子类Callback类的实现是在WifiStateMachine中实现的。
class IpManagerCallback extends IpManager.Callback {
.......@Override
public void onReachabilityLost(String logMsg) {
sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
}
.......
}
上面的分析的LOST_PROVISIONING 处理逻辑如下:
IpReachabilityMonitor: LOST_PROVISIONING -> mCallback.notifyLost(ip, logMsg);
IpManager: mCallback.onReachabilityLost(String logMsg)
WifiStateMachine: sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
WifiStateMachine
此处主要关注WifiStateMachine中对CMD_IP_REACHABILITY_LOST命令的处理。
1、状态机对CMD_IP_REACHABILITY_LOST命令的处理
该消息的处理仅在WifiStateMachine的状态机中,有两个状态会处理DefaultState和L2ConnectedState。
在DefaultState中,接收到CMD_IP_REACHABILITY_LOST命令直接丢弃不处理:
class DefaultState extends State {
@Override
public boolean processMessage(Message message) {
....
case CMD_IP_REACHABILITY_LOST:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
break;
....
}
在L2ConnectedState状态中,接收到CMD_IP_REACHABILITY_LOST命令处理:
class L2ConnectedState extends State {
.....
@Override
public boolean processMessage(Message message) {
switch (message.what) {
......
case CMD_IP_REACHABILITY_LOST:
///M: ALPS02475594 Ignore ip reachability lost for improving performance
//由于一些特殊使用场景,比如使用Wi-Fi Display时为了提高Wi-Fi Tput ,可能需要临时暂停Wi-Fi 一段时间的Scan和重连动作。此时就会忽视ignore CMD_IP_REACHABILITY_LOST命令,不做任何处理。
if (isTemporarilyDontReconnectWifi()) {
//如果临时暂定Wi-Fi的扫描和重连功能,直接丢弃CMD_IP_REACHABILITY_LOST命令不做任何处理
log("isTemporarilyDontReconnectWifi is true, " +"ignore CMD_IP_REACHABILITY_LOST");
} else if (enableIpReachabilityMonitor()) {
//如果已经使能了IpReachabilityMonitor机制功能,系统默认使能
if (!enableIpReachabilityMonitorEnhancement() || mIsListeningIpReachabilityLost
|| ((mIpManager != null) && (mIpManager.getLostCount() >= 3))) {
//这里满足三个条件任何一个就执行下面的操作
handleIpReachabilityLost();
transitionTo(mDisconnectingState);
}
else {///如下这段MTK添加的patch, 由于在上一个if条件中已经有了
mIsListeningIpReachabilityLost为true的情况,所以此段代码永远不会执行,为无效代码。
///M: ALPS02550356 Avoid frequently disconnect caused by ip // reachability lost @{
Log.d(TAG, "mIsListeningIpReachabilityLost: "+ mIsListeningIpReachabilityLost);
if (mIsListeningIpReachabilityLost) {
handleIpReachabilityLost();
transitionTo(mDisconnectingState);
} else {
Log.d(TAG, "Ignore CMD_IP_REACHABILITY_LOST");
}
}
}else {//如果没有使能 IpReachabilityMonitor机制功能,直接丢弃CMD_IP_REACHABILITY_LOST命令不做任何处理
Log.d(TAG, "Ignore CMD_IP_REACHABILITY_LOST " +"due to enableIpReachabilityMonitor is off");
}
break;
.....
}
从上面的代码可以看出,WifiStateMachine 中的消息CMD_IP_REACHABILITY_LOST在使能IpReachabilityMonitor的情况下,只要满足三个条件中一个,就执行handleIpReachabilityLost(),并且状态机由L2ConnectedState进入DisconnectingState.
这三个条件分别解释如下:
!enableIpReachabilityMonitorEnhancement() //这个由系统属性persist.wifi.IRM.enhancement和com.mediatek.internal.R.bool.config_enable_ip_reachability_monitor_enhancement 两个值控制,其实这个条件就是MTK自己基于Google Android原生添加的,该条件为True的意思是系统属性和MTK的配置变量均置为了False了。
mIsListeningIpReachabilityLost //这个也是MTK自己基于Google Android 原生添加的,跟上面的一样。为True的意思是已经启动开始监听IpReachabilityLost的功能。
((mIpManager != null) &&(mIpManager.getLostCount() >= 3)) //这个也是基于Android 原生自己新增的控制条件,主要用于控制出现3次IP LOST_PROVISIONING(CMD_IP_REACHABILITY_LOST)时,才执行handleIpReachabilityLost(); 主要是为了避免由于芯片级不稳定,驱动频繁发出IP LOST_PROVISIONING, 从而带来上层频繁断线,用户体验很差。当然这个仅算是一个避归方案。真正的问题出现在芯片驱动上。
2、handleIpReachabilityLost()操作
// TODO: De-duplicated this and handleIpConfigurationLost().
private void handleIpReachabilityLost() {
//清空当前网络的mIpAddress
mWifiInfo.setInetAddress(null);
//将WifiInfo中mMeteredHint置为false。该变量表示相应的网络的上游连接被计量了(该网络需要按流量收费的意思),对于大数据传输很敏感。
mWifiInfo.setMeteredHint(false);
//发送一个广播出去,应用层获取广播后,友善提示用户当前网络已经断开
sendBroadcastForErrorNetwork();
// Disconnect via supplicant, and let autojoin retry connecting to the network.
//将Supplicant连接也断开,即完全断开网络,让其执行重连动作。
mWifiNative.disconnect();
}
总结
至此,Android 中由于IpReachabilityMonitor 监视到Kernel上报当前网络配置丢失(LOST_PROVISIONING)的处理完整流程介绍完毕,总结如下:
IpReachabilityMonitor:LOST_PROVISIONING -> mCallback.notifyLost(ip, logMsg);
|
IpManager:mCallback.onReachabilityLost(String logMsg)
|
WifiStateMachine:sendMessage(CMD_IP_REACHABILITY_LOST, logMsg);
|
WifiStateMachine:handleIpReachabilityLost()
最终从清除当前网路在WifiInfo中Ip地址信息,并置其mMeteredHint属性为false,然后下发Supplicant断开当前网络。
......