android wifi之ConnectivityService
在查看了wifiStateTracker源码之后,发现在startMonitoring函数注册的广播里向connectivityService的handler发送了message,我们已知在ConnectivityService的构造函数里面曾经开启了wifiStateTracker的startMonitoring函数以接受广播,现在就来看看connectivityService类。
首先看它的内部类MyHandler。handleMessage方法中的case方法,1.EVENT_STATE_CHANGED 它接收了所有的stateTracker中发送的消息,
case NetworkStateTracker.EVENT_STATE_CHANGED: if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
handleConnectionFailure(info);
} else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) {
handleDisconnect(info); } else if (state == NetworkInfo.State.CONNECTED) {
handleConnect(info); }
break;
DISCONNECTED和SUSPENDED處理方法基本相同只不过在处理sunpended时发送了一个广播。我们先来了解下handleDisconnect()方法,源码中对着个函数是这样介绍的:我将该方法进行拆块分析,贴源码:
int prevNetType = info.getType();
mNetTrackers[prevNetType].setTeardownRequested(false); /* * If the disconnected network is not the active one, then don't report * this as a loss of connectivity. What probably happened is that we're * getting the disconnect for a network that we explicitly disabled * in accordance with network preference policies. */ if (!mNetConfigs[prevNetType].isDefault()) { List pids = mNetRequestersPids[prevNetType]; for (int i = 0; i<pids.size(); i++) { Integer pid = (Integer)pids.get(i); // will remove them because the net's no longer connected // need to do this now as only now do we know the pids and // can properly null things that are no longer referenced. reassessPidDns(pid.intValue(), false); } }
首先获得网络类型,这里先了解下mNetRequestersPids ,它是在函数public int startUsingNetworkFeature(int networkType, String feature,IBinder binder)里面添加进去的,至于这个函数对应ConnecTivityManager里面的函数,在做网络开发时应该会用到,下面再研究这个函数吧,现在先看遍历这些pids调用了reassessPidDns(pid.intValue(), false); 函数都干什么了:
private void reassessPidDns(int myPid, boolean doBump) { if (VDBG) log("reassessPidDns for pid " + myPid); for(int i : mPriorityList) { if (mNetConfigs[i].isDefault()) { continue; } NetworkStateTracker nt = mNetTrackers[i]; if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { LinkProperties p = nt.getLinkProperties(); if (p == null) continue; List pids = mNetRequestersPids[i]; for (int j=0; j<pids.size(); j++) { Integer pid = (Integer)pids.get(j); if (pid.intValue() == myPid) { Collection<InetAddress> dnses = p.getDnses(); writePidDns(dnses, myPid); if (doBump) { bumpDns(); } return; } } } } // nothing found - delete for (int i = 1; ; i++) { String prop = "net.dns" + i + "." + myPid; if (SystemProperties.get(prop).length() == 0) { if (doBump) { bumpDns(); } return; } SystemProperties.set(prop, ""); } }
对该函数的说明为 Adjust the per-process dns entries (net.dns<x>.<pid>) based on the highest priority active net which this process requested. If there aren't any, clear it out。
第一个for以优先权遍历所有网络类型找到符合条件(该网络链接存在,有可能传输数据,且没有被tear down)的网络,再对该网络遍历所有的pids(process id 是system server所有)找到目标参数mypid执行函数writePidDns(dnses, myPid);这个函数是向android系统属性里的开机导入的cache属性写入该网络的ip地址及dns等(前提是该网络没有被写进这个属性)。写入之后changed属性就变为true,这样在每次开机init之后,会执行一个loop循环然后若有改变则会更新。这里doBump为false不执行,因此看下面的那个for循环,这个循环里bumpDns也不执行,而只是将有该pid的所有ip链接清空(第一个for循环return了,就不会执行它了)。bumpDns函数是用以提醒重新从系统属性里面读DNS服务器名单。
下面继续handleDisconnect函数讲解,接下来给参数doReset赋值决定是否改变网络接口名称,(若网络中有重名接口则doReset赋值为false)随后调用了handleConnectivityChange方法(prevNetType, doReset),并发送了一个广播该广播是发送给NetWorkStateService的通知网络接口名称改变了。
至于handleConnecthandleConnect(NetworkInfo info)函数首先判断传进的网络是否为默认网络,若是,且mActiveDefaultNetwork已经设置,且目标type网络不是mActiveDefaultNetwork网络则进入
if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { if ((type != mNetworkPreference && mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority) || mNetworkPreference == mActiveDefaultNetwork) { // don't accept this one if (VDBG) { log("Not broadcasting CONNECT_ACTION " + "to torn down network " + info.getTypeName()); } teardown(thisNet); return; // sunxz begin 2012-2-4 for pppoe } else if(type != ConnectivityManager.TYPE_PPPOE){ // sunxz end 2012-2-4 for pppoe // tear down the other NetworkStateTracker otherNet = mNetTrackers[mActiveDefaultNetwork]; if (DBG) { log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + " teardown"); } if (!teardown(otherNet)) { loge("Network declined teardown request"); teardown(thisNet); return; } }}
在该段函数里(第一个if里)第一个判断是说如果目标type网络不是preference网络且正在运行的网络优先级大于type网络则,或者正在运行的网络是preference网络则关闭(tear down)type网络。else if判断是说若type网络类型若不是pppoe就tear down otherNet或者typeNet,注意进入这两个都会执行return若没有被return则会继续往下执行,看源码:
synchronized (ConnectivityService.this) {
if (mNetTransitionWakeLock.isHeld()) { mHandler.sendMessageDelayed(mHandler.obtainMessage( EVENT_CLEAR_NET_TRANSITION_WAKELOCK, mNetTransitionWakeLockSerialNumber, 0), 1000); } }
这段代码首先判断屏幕是否亮着,若亮着,一秒种之后关闭屏幕,之所以一秒钟之后关闭是留给应用程序连接新网络所用的时间。这里面我的想法:代码能执行到这里是因为没有被return,也就是没有关闭type网络(新网络),也就是说新的网络被允许链接了。首先wpa_supplicant扫描出网络状态改变了,然后发消息给wifiStatemachine,然后wifistatemachine收到消息,用wifiNative enable新的网络,然后发广播给wifistateTRacker,在wifiStateTracker的onReiceive方法里面再给connectivityService的handler发送message就到了这里了,应该说这个函数的处理就是看连接上的网络是否符合条件若不符合就直接tear down。
继续往下看代码:
mActiveDefaultNetwork = type;
// this will cause us to come up initially as unconnected and switching // to connected after our normal pause unless somebody reports us as reall // disconnected mDefaultInetConditionPublished = 0; mDefaultConnectionSequence++; mInetConditionChangeInFlight = false; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); } thisNet.setTeardownRequested(false); updateNetworkSettings(thisNet); handleConnectivityChange(type, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
}
首先将正在运行的网络的类型改为type,然后再更新一下变量。updateNetworkSettings(thisNet)函数是从系统属性里面读出该网络的属性信息然后把它写到"/sys/kernel/ipv4/tcp_"里面。至此handleConnect函数已经分析完毕了。
下面看函数handleConnectionFailure(NetworkInfo info) Called when an attempt to fail over to another network has failed. @param info the {@link NetworkInfo} for the failed network
if (mNetConfigs[info.getType()].isDefault()) { tryFailover(info.getType()); if (mActiveDefaultNetwork != -1) { NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } }
该段代码的核心是tryFailover(info.getType()); 它会依次对记录的所有网络都尝试进行连接,mActiveDefaultNetwork != -1说明在handleConnect函数里已经修改了它的值,即有可用的连接,随后发一条广播通知说已经连接上网络了。handleConnectionFailure不同于handleDisconnected,前者是连接失败,后者是IP连接不可用,前者里面相对与后者没有向SystemProperty里面写信息,也没有改网络接口名称,也没有执行handleConnectivityChange函数。