android wifi之ConnectivityService
在查看了wifiStateTracker源码之后,发现在startMonitoring函数注册的广播里向connectivityService的handler发送了message,我们已知在ConnectivityService的构造函数里面曾经开启了wifiStateTracker的startMonitoring函数以接受广播,现在就来看看connectivityService类。
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 (!mNetConfigs[prevNetType].isDefault()) { List pids = mNetRequestersPids[prevNetType]; for (int i = 0; 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
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; jif (pid.intValue() == myPid) { Collection 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, ""); } }
第一个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
至于handleConnecthandleConne
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, mNetTransitionWakeLockSe rialNumber, 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 mDefaultInetConditionPub lished = 0; mDefaultConnectionSequen ce++; mInetConditionChangeInFl ight = false; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); } thisNet.setTeardownRequested(false); updateNetworkSettings(thisNet); handleConnectivityChange (type, false); sendConnectedBroadcastDe layed(info, getConnectivityChangeDel ay());
}
首先将正在运行的网络的类型改为type,然后再更新一下变量。updateNetworkSettings(thisNet)函数是从系统属性里面读出该网络的属性信息然后把它写到"/sys/kernel/ipv4/tcp_"里面。至此handleConnect函数已经分析完毕了。
下面看函数handleConnectionFailure(NetworkInfo info)
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