在查看了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函數。
