我们知道,当手机在使用移动数据上网时,如果进入WIFI环境,手机将会自动连上WIFI使用数据,而当WIFI失去覆盖或者关闭WIFI时,手机又会自动连上移动数据,那么这个机制是如何实现的呢?本文从WIFI框架触发,跟踪当WIFI被disconnect时,如何切换为数据网络。
private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) { boolean hidden = false; if (state != mNetworkInfo.getDetailedState()) { //更新NetworkInfo的状态 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); if (mNetworkAgent != null) { //将最新状态发送到NetworkAgent mNetworkAgent.sendNetworkInfo(mNetworkInfo); } sendNetworkStateChangeBroadcast(null); return true; } return false; }
到这里就不得不介绍一下NetworkInfo和NetworkAgent了。
@NetworkInfo.java //获取网络类型,TYPE_MOBILE/TYPE_WIFI/TYPE_MOBILE_MMS等 public int getType() {} //获取网络类型名称 public String getTypeName() {} //网络是否是CONNECTED或者CONNECTING状态 public boolean isConnectedOrConnecting() {} //网络是否是CONNECTED状态 public boolean isConnected() {} //设置网络是否可用 public void setIsAvailable(boolean isAvailable) {} //判断网络是否可用 public boolean isAvailable() {} //是否漫游状态 public boolean isRoaming() {} //设置漫游状态 public void setRoaming(boolean isRoaming) {} //获取网络的state、mReason等信息 public DetailedState getDetailedState() {}应用程序可以 通过ConnectivityManager的getNetworkInfo()方法获取到该对象,并通过该对象查询当前的网络状态,比如可以这样获取当前是否有网络连接:
private boolean isNetworkConnected() { final ConnectivityManager connectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivity == null) { return false; } final NetworkInfo info = connectivity.getActiveNetworkInfo(); return info != null && info.isConnected(); }上面是应用读取NetworkInfo的方法,那么当网络变化时,就应该由WIFI或者DATA去更新当前的NetworkInfo,而WifiStateMachine在setNetworkDetailedState中做的就是把当前的网络状态更新到NetworkInfo,即:
mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID());
更新完NetworkInfo之后,需要将其更新到ConnectivityManager才可被其他应用读取到,那么如何将其更新到ConnectivityManager呢?这就需要NetworkAgent来完成了。
"A Utility class for handling for communicating between bearer-specific code and ConnectivityService."这句话描述了NetworkAgent的作用: 他是某个网络连接与ConnectivityService之间的通讯的工具。
public abstract class NetworkAgent extends Handler {}我们发现,这是一个Handler的子类,并且他是一个抽象类(abstract), 需要在子类中被实例化。
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { this(looper, context, logTag, ni, nc, lp, score, null); } public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { super(looper); mContext = context; if (ni == null || nc == null || lp == null) { throw new IllegalArgumentException(); } //获取ConnectivityManager对象,并向其注册自己 ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); }我们看到其构造方法里面主要做了一件事情,获取ConnectivityManager对象,并通过registerNetworkAgent方式注册当前的NetworkAgent。
接下来我们插入两节来分别介绍另外两个对象:ConnectivityManager和ConnectivityService,然后再回头来看这里的registerNetworkAgent()方法。
@SystemServer.java public static final String CONNECTIVITY_SERVICE = "connectivity"; private void startOtherServices() { try { //创建ConnectivityService connectivity = new ConnectivityService(context, networkManagement, networkStats, networkPolicy); //注册的name为"connectivity" ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); } }
从上面知道,该Service在SystemServer中的name为"Connectivity"。知道了这一点就够了,至于ConnectivityService本身我们暂且不去关注。
@ContextImpl.java registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE); return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b)); }});从这里我们看到,创建ConnectivityManager时传递了一个name为CONNECTIVITY_SERVICE的服务对象,这个对象就是刚才我们向SystemServer注册的ConnectivityService。然后来看ConnectivityManager的构造方法:
@ConnectivityManager.java public ConnectivityManager(IConnectivityManager service) { mService = checkNotNull(service, "missing IConnectivityManager"); }这里我们看到,构造方法里面只是将参数ConnectivityService传递给mService对象就完了。
好了,ConnectivityManager我们了解这么多就够了。下面继续我们NetworkAgent的初始化流程。
现在我们继续NetworkAgent的初始化流程,这个流程中包含AsyncChannel的使用,不了解的同学可以在这里了解其使用方法和机制。
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { super(looper); mContext = context; if (ni == null || nc == null || lp == null) { throw new IllegalArgumentException(); } //获取ConnectivityManager对象,并向其注册自己 ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); }在调用注册方法时传递了六个参数,其中有三个比较重要的参数,都是从构造方法的参数中获取并重新new出来的,其分别是:
@ConnectivityManager.java public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc) { try { mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc); } catch (RemoteException e) { } }经过前面的介绍我们现在知道,这里的mService就是ConnectivityService,继续来看接下来的流程:
@ConnectivityService.java public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) { //权限检查 enforceConnectivityInternalPermission(); //创建NetworkAgentInfo对象 NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc)); synchronized (this) { nai.networkMonitor.systemReady = mSystemReady; } //向自己Handler发送EVENT_REGISTER_NETWORK_AGENT消息 mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); }在ConnectivityService的registerNetworkAgent中做了两件事情:
private class InternalHandler extends Handler { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case EVENT_REGISTER_NETWORK_AGENT: { handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj); break; } } } }继续看handleRegisterNetworkAgent():
private void handleRegisterNetworkAgent(NetworkAgentInfo na) { mNetworkAgentInfos.put(na.messenger, na); assignNextNetId(na); //向NetworkAgentInfo的asyncChannel对象发起连接请求 na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; na.networkInfo = null; updateNetworkInfo(na, networkInfo); }这里我们看到,ConnectivityService向NetworkAgentInfo的asyncChannel对象发起connect请求,并且 该AsyncChannel的srcHandler是mTrackerHandler,而dstMessenger对象是NetworkAgentInfo的messenger,那么这里的NetworkAgentInfo是哪里来的呢?
接下来,ConnectivityService将会利用获取到的NetworkAgent对象创建AsyncChannel双向通道。
@NetworkAgent.java public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); }因此 ConnectivityService中的dstMessenger其实就是NetworkAgent,准确来说应该是NetworkAgent的子类。
private class NetworkStateTrackerHandler extends Handler { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { handleAsyncChannelHalfConnect(msg); break; } } } }继续来看handleAsyncChannelHalfConnect:
private void handleAsyncChannelHalfConnect(Message msg) { AsyncChannel ac = (AsyncChannel) msg.obj; if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { //向AsyncChannel发送消息 mNetworkAgentInfos.get(msg.replyTo).asyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); } else { } } }这里我们看到,此刻ConnectivityService通过AsyncChannel向dstMessenger发送了CMD_CHANNEL_FULL_CONNECTION的消息,从AsyncChannel的机制我们想到,这个消息应该是在向NetworkAgent申请 双向通道。
class L2ConnectedState extends State { @Override public void enter() { mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, mLinkProperties, 60); } }然后来看该WifiNetworkAgent的定义:
@WifiStateMachine.java private class WifiNetworkAgent extends NetworkAgent { public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { super(l, c, TAG, ni, nc, lp, score); } protected void unwanted() { if (this != mNetworkAgent) return; unwantedNetwork(network_status_unwanted_disconnect); } protected void networkStatus(int status) { if (status == NetworkAgent.INVALID_NETWORK) { unwantedNetwork(network_status_unwanted_disable_autojoin); } } }从这里我们看到,WifiNetworkAgent并没有覆盖父类NetworkAgent中的handleMessage方法,那么也就是说,当ConnectivityService向WifiNetworkAgent发送AsyncChannel请求时,该请求应该在NetworkAgent中被处理,也就是这里:
@NetworkAgent.java public void handleMessage(Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { if (mAsyncChannel != null) { } else { //创建WifiNetworkAgent中的AsyncChannel对象 AsyncChannel ac = new AsyncChannel(); //完成双向通道连接动作 ac.connected(null, this, msg.replyTo); ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, AsyncChannel.STATUS_SUCCESSFUL); synchronized (mPreConnectedQueue) { mAsyncChannel = ac; for (Message m : mPreConnectedQueue) { ac.sendMessage(m); } mPreConnectedQueue.clear(); } } break; } } }从这个handleMessage()中我们看到,对于ConnectivityService发起的CMD_CHANNEL_FULLY_CONNECTED申请,WifiNetworkAgent创建了自己的AsyncChannel对象并连接上然后发送了STATUS_SUCCESSFUL的消息。
private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) { boolean hidden = false; if (state != mNetworkInfo.getDetailedState()) { //更新NetworkInfo的状态 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); if (mNetworkAgent != null) { //将最新状态发送到NetworkAgent mNetworkAgent.sendNetworkInfo(mNetworkInfo); } sendNetworkStateChangeBroadcast(null); return true; } return false; }然后我们来看NetworkAgent如何将最新的networkInfo传递到ConnectivityService中去:
@NetworkAgent.java public void sendNetworkInfo(NetworkInfo networkInfo) { queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); }继续:
private void queueOrSendMessage(int what, Object obj) { synchronized (mPreConnectedQueue) { if (mAsyncChannel != null) { //通过AsyncChannel发送请求 mAsyncChannel.sendMessage(what, obj); } else { Message msg = Message.obtain(); msg.what = what; msg.obj = obj; mPreConnectedQueue.add(msg); } } }到这里我们发现,NetworkAgent将最新的NetworkInfo作为一个Object放入一个EVENT_NETWORK_INFO_CHANGED的消息中,然后通过AsyncChannel发送出去。那么这个消息发送到哪里了呢?
@ConnectivityService.java private class NetworkStateTrackerHandler extends Handler { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: { //拿到消息中最新的NetworkInfo信息 NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); if (nai == null) { loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent"); break; } info = (NetworkInfo) msg.obj; //通过updateNetworkInfo来进行更新 updateNetworkInfo(nai, info); break; } } } }然后我们继续来看updateNetworkInfo()的操作:
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) { NetworkInfo.State state = newInfo.getState(); NetworkInfo oldInfo = null; synchronized (networkAgent) { oldInfo = networkAgent.networkInfo; //将最新的networkInfo更新到ConnectivityService networkAgent.networkInfo = newInfo; } if (state == NetworkInfo.State.CONNECTED && !networkAgent.created) { } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) { //断开WIFI的NetworkAgent中的AsyncChannel networkAgent.asyncChannel.disconnect(); } }在updateNetworkInfo()中,ConnectivityService将最新的NetworkInfo保存在networkAgent中,等待其他应用来获取。然后就向NetworkAgent的AsyncChannel发起disconnect()的请求,该请求将会在ConnectivityService中收到CMD_CHANNEL_DISCONNECTED的回应:
private class NetworkStateTrackerHandler extends Handler { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { handleAsyncChannelDisconnected(msg); break; } } } }继续来看handleAsyncChannelDisconnected():
private void handleAsyncChannelDisconnected(Message msg) { NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); if (nai != null) { final ArrayList<NetworkAgentInfo> toActivate = new ArrayList<NetworkAgentInfo>(); for (int i = 0; i < nai.networkRequests.size(); i++) { //当前网络断开,寻找可替代的网络连接 NetworkRequest request = nai.networkRequests.valueAt(i); NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { mNetworkForRequestId.remove(request.requestId); sendUpdatedScoreToFactories(request, 0); NetworkAgentInfo alternative = null; } } } }在这里,将会取出当前断开的网络所能处理的NetworkRequest,然后在当前所有向ConnectivityService注册的列表中查找可替代的连接,并通过sendUpdatedScoreToFactories()向其发起连接请求:
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) { for (int i = 0; i < nai.networkRequests.size(); i++) { NetworkRequest nr = nai.networkRequests.valueAt(i); if (!isRequest(nr)) continue; sendUpdatedScoreToFactories(nr, nai.getCurrentScore()); } }继续:
private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, networkRequest); } }到这里将会向新的连接的NetworkFactoryInfo对象发起CMD_REQUEST_NETWORK的请求,之后相应的连接对象就可以建立连接了。