Android 中的WiFi剖析

Android的WiFi java

咱們一般看到WiFi的守護進程wpa_supplicant在咱們的ps的進程列表中,這個就是咱們的wifi守護進程。wpa_supplicant在external/wpa_supplicant裏實現 linux

wpa_supplicant適配層是通用的wpa_supplicant的封裝,在Android中做爲WIFI部分的硬件抽象層來使用。wpa_supplicant適配層主要用於封裝與wpa_supplicant守護進程的通訊,以提供給Android框架使用。它實現了加載,控制和消息監控等功能。 android

wpa_supplicant適配層的頭文件以下所示: 數據庫

hardware/libhardware_legacy/include/hardware_legacy/wifi.h 服務器

咱們看它的加載過程 網絡

Init會在系統啓動首先加載init.rc這個文件會加載全部service,這是linux啓動的第一個用戶空間的應用(屬於linux進程,不屬於Android應用)。 併發

Service wpa_supplicant /system/bin/wpa_supplicant –Dwext –iwlan0 –d –c /data/misc/wifi/wpa_supplicant.conf app

#user wifi 框架

#group wifi system less

Socket wpa_eth0 dgram 0660 wifi system

Disabled

Oneshot

Serive dhcpcd /system/bin/dhcpcd –f /system/etc/dhcpcd/dhcpcd.conf –d eth0

Disabled

Onshot

On property:init.svc.wpa_supplicant=stopped

Stop dhcpcd

添加/system/etc/wifi/wpa_supplicant.conf

Update_config=1

Ctrl_interface=/data/system/wpa_supplicant //和IFACE_DIR對應

Eapol_verison=1

Ap_scan=1

Fast_reauth=1

經過linux內核模塊/system/lib/modules/wlan.ko 這個wifi模塊定義在/hardware/libhardware_legacy/wifi/wifi.c

當SystemServer啓動後會加載一系列的Service其中init2啓動的就有ConnectivityService。ConnectivityService.java (frameworks/base/services/java/com/android/server)會管理全部的Connectivity相關的好比APN,WiFi。看看是怎麼啓動WiFi Service的:

if (DBG) Log.v(TAG, "Starting Wifi Service.");

WifiStateTracker wst = new WifiStateTracker(context, mHandler);

WifiService wifiService = new WifiService(context, wst);

ServiceManager.addService(Context.WIFI_SERVICE, wifiService);

WifiStateTracker會建立WifMonitor來接受來自底層的事件。WifiService和WifiMonitor是整個模塊的核心部分,WifiService負責啓動關閉wpa_supplicant、發命令給wpa_supplicant進程,WiFiMonitor負責從wpa_supplicant接收事件

整個流程是

SystemServer -> ServerThread -> ConnectivityService -> ConnectivityThread -> WifiTracker->WifiService -> WifiMonitor

WiFi 的啓動過程

用戶在設置界面下開啓了WiFi,調用應用程序Settings中的setWifiEnabler的onPerferenceChange,再由WifiEnable調用WifiService,發送MESSAGE_ENABLE_WIFI,首先裝載wifi內核模塊wlan.ko而後啓動wpa_supplicant(用/data/misc/wifi/wpa_supplicant.conf配置),再經過WifiStateTracker來啓動WifiMonitor監視線程

WifiSettings.java (packages/apps/settings/src/com/android/settings/wifi)啓動

mWifiEnabled = (CheckBoxPreference) preferenceScreen.findPreference(KEY_WIFI_ENABLED);

mWifiEnabler = new WifiEnabler(this, (WifiManager) getSystemService(WIFI_SERVICE),

mWifiEnabled);

這樣就啓動WifiEnabler

WifiEnabler.java (packages/apps/settings/src/com/android/settings/wifi)經過WifiManager調用WifiManager.java (frameworks/base/wifi/java/android/net/wifi) setWifiEnabled 中的 IWifiManager來啓動wifiservice[mService.setWifiEnabled(enabled);]

WifiService.java (frameworks/base/services/java/com/android/server)又setWifiEnabled()這個裏面的sendEnableMessage(enable, true, Binder.getCallingUid());來發送一則消息

Message msg = Message.obtain(mWifiHandler,

(enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),

(persist ? 1 : 0), uid);

msg.sendToTarget();發送給自身的消息。

經過WifiHandler的 handleMessage來維護這些消息,enable的時候會調用setWifiEnabledBlocking這個函數,這個函數會作setWifiEnabledState 而後作兩件事: 1. 調用wifi 本地方法JNI的WifiNative.loadDriver

下面說本地方法WifiNative.loadDriver函數 WifiNative.java (frameworks/base/wifi/java/android/net/wifi) Android的WIFI系統的JNI的部分:

frameworks/base/core/jni/android_net_wifi_Wifi.cpp 中的android_net_wifi_loadDriver()能夠把wifi驅動模塊裝載

Wifi.c (hardware/libhardware_legacy/wifi) 內核模塊/system/lib/modules/wlan.ko中的wifi_load_driver()

設置wlan.driver.status屬性爲ok,至此wifi模塊加載完畢。

2. 再來看看啓動,一樣是在WifiService 中的setWifiEnabledBlocking這個函數會調用startSupplicant 經過WifiNative.java (frameworks/base/wifi/java/android/net/wifi)的startSupplicant來啓動JNI:frameworks/base/core/jni/android_net_wifi_Wifi.cpp的android_net_wifi_startSupplicant調用驅動模塊Wifi.c (hardware/libhardware_legacy/wifi) wlan.ko中的wifi_start_supplicant, Wifi 啓動完畢

成功啓動wifi以後setWifiEnabledBlocking運行mWifiStateTracker.startEventLoop();事件循環,來監視事件mWifiMonitor.startMonitoring(); à MonitorThread().start();一直在線程裏循環調用WifiNative.waitForEvent();最後調用

setWifiEnabledState(eventualWifiState, uid); intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);廣播消息向外界通知wifi已經成功啓動了。

查找熱點AP

上面說了WifiManager發送廣播WIFI_STATE_CHANGED_ACTION,只要Android應用註冊了接受該Action的就接受,咱們的WifiLayer註冊了接收到該Action

WifiSettings.java (packages/apps/settings/src/com/android/settings/wifi)中有mWifiLayer.onCreate();(這個函數建立WifiLayer指定接受的Action)

WifiLayer.java (packages/apps/settings/src/com/android/settings/wifi)中的BroadcastReceiver 有一句話else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {

handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,

WifiManager.WIFI_STATE_UNKNOWN));

這個函數會調用loadConfiguredAccessPoints和attemptScan來開始掃描,調用WifiManager的mWifiManager.startScanActive,WifiManager.java中的mService.startScan經過WifiService中的startScan經過本地方法WifiNative.setScanResultHandlingCommand啓動JNI android_net_wifi_Wifi.cpp (frameworks/base/core/jni) 中的android_net_wifi_setScanResultHandlingCommand的命令「AP_SCAN 模式」 Wifi.c ::wifi_command(cmd)開始掃描wifi_send_command發出SCAN命令調用wpa_supplicant開始掃描

掃描完成以後會發送SCAN_RESULT 在WifiMonitor的HandleEvent裏處理調用mWifiStateTracker.notifyScanResultsAvailable(); à sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE); mWifiStateTracker中的 handleMessage接收到case EVENT_SCAN_RESULTS_AVAILABLE:以後發送廣播mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

WiFiLayer接收到這個消息在mReceiver = new BroadcastReceiver()中處理handleScanResultsAvailable();

WiFi 鏈接流程

用戶在AccessPointDialog中輸入密碼以後點擊鏈接按鈕,Android調用順序以下:

AccessPointDialog.java (packages/apps/settings/src/com/android/settings/wifi) -> onClick -> handleConnect(); -> mWifiLayer.connectToNetwork ->經過WifiConfiguration config = findConfiguredNetwork(state);查看是否是配置過的,若是是就直接使用了,若是不是config = addConfiguration(state, 0); -> managerEnableNetwork -> mWifiManager.enableNetwork -> mService.enableNetwork -> WifiService. enableNetwork -> WifiNative.enableNetworkCommand -> JNI: android_net_wifi_Wifi.cpp android_net_wifi_enableNetworkCommand 調用wpa_suppcant發送相關命令返回以後由WiFiMonitor處理跟之前相似,鏈接的中間流程與查找AP的流程相似,都通過了WifiMonitor對「CONNECTED」消息響應的捕獲,以及WifiStateTracker對EVENT_SUPPLICANT_STATE_ CHANGED的處理。還有一個比較重

要的步驟是WifiStateTracker經過對DHCP服務器的申請進行了IP地址分配。最終會廣播NETWORK_STATE_CHANGED_ ACTION消息,由WifiLayer響應。

IP地址分配

由上面繼續說IP地址分配,由於當wpa_supplicant連接AP成功以後,它會發出事件從而wifi_for_event函數會接收到該事件,由WifiMonitor中的MonitorThread執行執行這個事件handleEvent-> case CONNECTED: handleNetworkStateChange -> mWifiStateTracker.notifyStateChange -> EVENT_NETWORK_STATE_CHANGED -> handleMessage 下的:case EVENT_SUPPLICANT_STATE_CHANGED: -> intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); Wi-Fi supplicant state changed:

èSettingsObserver專門是觀察該類變化的

if (changed) {

resetInterface(true);

configureInterface();

if (mUseStaticIp) {

mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);

}

}

è

mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);

->

DhcpHandler的handleMessage函數case EVENT_DHCP_START: NetworkUtils.runDhcp獲取DHCP的IP地址,成功以後發送EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:

event經過WifiStateTracker的HandleMessage函數case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:會調用sendNetworkStateChangeBroadcast Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);發送全局Intent Action 完成網絡切換。

-------------------------------------------------------------------WIFI啓動 代碼流程走讀

初始化
在 SystemServer 啓動的時候,會生成一個 ConnectivityService 的實例 ,
try {
Log.i(TAG, "Starting Connectivity Service.");
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, new
ConnectivityService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Connectivity Service", e);
}
ConnectivityService 的構造函數 會建立 WifiService,
if (DBG) Log.v(TAG, "Starting Wifi Service.");
mWifiStateTracker = new WifiStateTracker(context, handler);
WifiService wifiService = new WifiService(context, mWifiStateTracker);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
WifiStateTracker 會建立 WifiMonitor 接收來自底層的事件,WifiService 和 WifiMonitor 是整
個模塊的核心 。WifiService 負責啓動關閉 wpa_supplicant、啓動關閉 WifiMonitor 監視線程
和把命令 下發給 wpa_supplicant,而 WifiMonitor 則負責從 wpa_supplicant 接收事件通知。
鏈接 AP
1. 使能 WIFI
WirelessSettings 在初始化的時候配置了由 WifiEnabler 來處理 Wifi 按鈕,
private void initToggles() {
mWifiEnabler = new WifiEnabler(
this,
(WifiManager) getSystemService(WIFI_SERVICE),
(CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI));
當用戶按下 Wifi 按鈕後, Android 會調用 WifiEnabler 的 onPreferenceChange, 再由 WifiEnabler
調用 WifiManager 的 setWifiEnabled 接口 函數,經過 AIDL,實際調用的是 WifiService 的
setWifiEnabled 函數,WifiService 接着向自身發送一條 MESSAGE_ENABLE_WIFI 消息,在
處理該消息的代碼 中作真正的使能工做:首先裝載 WIFI 內核模塊(該模塊的位置硬編碼爲
"/system/lib/modules/wlan.ko" ), 然 後 啓 動 wpa_supplicant ( 配 置 文 件 硬 編 碼 爲
"/data/misc/wifi/wpa_supplicant.conf") 再經過 WifiStateTracker 來啓動 WifiMonitor 中的監視
,
線程。
private boolean setWifiEnabledBlocking(boolean enable) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED :
WIFI_STATE_DISABLED;
updateWifiState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING);
if (enable) {
if (!WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fi driver.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
if (!WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
updateWifiState(WIFI_STATE_UNKNOWN);
return false;
}
mWifiStateTracker.startEventLoop();
}
// Success!
persistWifiEnabled(enable);
updateWifiState(eventualWifiState);
return true;
}
當使能成功後,會廣播發送 WIFI_STATE_CHANGED_ACTION 這個 Intent 通知外界 WIFI
已 經 成 功 使 能 了 。 WifiEnabler 創 建 的 時 候 就 會 向 Android 注 冊 接 收
WIFI_STATE_CHANGED_ACTION,所以它會收到該 Intent,從而開始掃描。
private void handleWifiStateChanged(int wifiState) {
if (wifiState == WIFI_STATE_ENABLED) {
loadConfiguredAccessPoints();
attemptScan();
}
2. 查找 AP
掃描的入口函數是 WifiService 的 startScan,它其實也就是往 wpa_supplicant 發送 SCAN 命
令。
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz)
{
jboolean result;
// Ignore any error from setting the scan mode.
// The scan will still work.
(void)doBooleanCommand("DRIVER SCAN-ACTIVE", "OK");
result = doBooleanCommand("SCAN", "OK");
(void)doBooleanCommand("DRIVER SCAN-PASSIVE", "OK");
return result;
}
當 wpa_supplicant 處理完 SCAN 命令後,它會向控制通道發送事件通知掃描完成,從而
wifi_wait_for_event 函數會接收到該事件,由此 WifiMonitor 中的 MonitorThread 會被執行來
出來這個事件,
void handleEvent(int event, String remainder) {
case SCAN_RESULTS:
mWifiStateTracker.notifyScanResultsAvailable();
break;
WifiStateTracker 則接着廣播發送 SCAN_RESULTS_AVAILABLE_ACTION 這個 Intent
case EVENT_SCAN_RESULTS_AVAILABLE:
mContext.sendBroadcast(new
Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
WifiLayer 註冊了接收 SCAN_RESULTS_AVAILABLE_ACTION 這個 Intent,因此它的相關
處理函數 handleScanResultsAvailable 會被調用,在該函數中,先會去拿到 SCAN 的結果(最
終是往 wpa_supplicant 發送 SCAN_RESULT 命令並讀取返回值來實現的) ,
List<ScanResult> list = mWifiManager.getScanResults();
對每個掃描返回的 AP,WifiLayer 會調用 WifiSettings 的 onAccessPointSetChanged 函數,
從而最終把該 AP 加到 GUI 顯示列表中。
public void onAccessPointSetChanged(AccessPointState ap, boolean added) {
AccessPointPreference pref = mAps.get(ap);
if (added) {
if (pref == null) {
pref = new AccessPointPreference(this, ap);
mAps.put(ap, pref);
} else {
pref.setEnabled(true);
}
mApCategory.addPreference(pref);
}
}
3. 配置 AP 參數
當用戶在 WifiSettings 界面上選擇了一個 AP 後,會顯示配置 AP 參數的一個對話框,
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference
preference) {
if (preference instanceof AccessPointPreference) {
AccessPointState state = ((AccessPointPreference)
preference).getAccessPointState();
showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
}
}
4. 鏈接
當用戶在 AcessPointDialog 中選擇好加密方式和輸入密鑰以後,再點擊鏈接按鈕,Android
就會去鏈接這個 AP。
private void handleConnect() {
String password = getEnteredPassword();
if (!TextUtils.isEmpty(password)) {
mState.setPassword(password);
}
mWifiLayer.connectToNetwork(mState);
}
WifiLayer 會先檢測這個 AP 是否是以前被配置過,這個是經過向 wpa_supplicant 發送
LIST_NETWORK 命令而且比較返回值來實現的,
// Need WifiConfiguration for the AP
WifiConfiguration config = findConfiguredNetwork(state);
若是 wpa_supplicant 沒有這個 AP 的配置信息, 則會向 wpa_supplicant 發送 ADD_NETWORK
命令來添加該 AP,
if (config == null) {
// Connecting for the first time, need to create it
config = addConfiguration(state,
ADD_CONFIGURATION_ENABLE|ADD_CONFIGURATION_SAVE);
}
ADD_NETWORK 命 令 會 返 回 一 個 ID , WifiLayer 再 用 這 個 返 回 的 ID 做 爲 參 數 向
wpa_supplicant 發送 ENABLE_NETWORK 命令,從而讓 wpa_supplicant 去鏈接該 AP。
// Make sure that network is enabled, and disable others
mReenableApsOnNetworkStateChange = true;
if (!mWifiManager.enableNetwork(state.networkId, true)) {
Log.e(TAG, "Could not enable network ID " + state.networkId);
error(R.string.error_connecting);
return false;
}
5. 配置 IP 地址
當 wpa_supplicant 成功鏈接上 AP 以後,它會向控制通道發送事件通知鏈接上 AP 了,從而
wifi_wait_for_event 函數會接收到該事件,由此 WifiMonitor 中的 MonitorThread 會被執行來
出來這個事件,
void handleEvent(int event, String remainder) {
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,
remainder);
break;
WifiMonitor 再調用 WifiStateTracker 的 notifyStateChange,WifiStateTracker 則接着會往自身
發送 EVENT_DHCP_START 消息來啓動 DHCP 去獲取 IP 地址,
private void handleConnectedState() {
setPollTimer();
mLastSignalLevel = -1;
if (!mHaveIPAddress & !mObtainingIPAddress) {
mObtainingIPAddress = true;
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();
}
}
而後再廣播發送 NETWORK_STATE_CHANGED_ACTION 這個 Intent
case EVENT_NETWORK_STATE_CHANGED:
if (result.state != DetailedState.DISCONNECTED || !mDisconnectPending) {
intent = new
Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExt ra(WifiManager.EXTRA_NETWORK_INFO,
mNetworkInfo);
if (result.BSSID != null)
intent.putExtra(WifiManager.EXTRA_BSSID, result.BSSID);
mContext.sendStickyBroadcast(intent);
}
break;
WifiLayer 註冊了接收 NETWORK_STATE_CHANGED_ACTION 這個 Intent,因此它的相關
處理函數 handleNetworkStateChanged 會被調用,
當 DHCP 拿到 IP 地址以後,會再發送 EVENT_DHCP_SUCCEEDED 消息,
private class DhcpHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DHCP_START:
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
event = EVENT_DHCP_SUCCEEDED;
}
WifiLayer 處 理 EVENT_DHCP_SUCCEEDED 消 息 , 會 再 次 廣 播 發 送
NETWORK_STATE_CHANGED_ACTION 這個 Intent,此次帶上完整的 IP 地址信息。
case EVENT_DHCP_SUCCEEDED:
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
setDetailedState(DetailedState.CONNECTED);
intent = new
Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
mContext.sendStickyBroadcast(intent);
break;
至此爲止,整個鏈接過程完成。
問題:
目前的實現不支持 Ad-hoc 方式。<!--++ plugin_code qcomic begin--> <!--++ plugin_code qcomic end-->

---------------------------------------------------------------------------------android 網絡鏈接管理

系統中對網絡的判斷和選在是在Connectivityervice這個服務中來處理的,在系統啓動的時候會啓動這個系統服務:系統啓動完畢後,ConnectivityService在系統啓動的時候就啓動了。在android內部,用framework/base/core/res/res/values/config.xml中定義了網絡的類型:<string-array translatable="false" name="networkAttributes"><item>"default,wifi,0"</item><item>"default,mobile,0"</item><item>"mms,mobile,1"</item><item>"supl,mobile,1"</item><item>"dun,mobile,1"</item><item>"hipri,mobile,2"</item></string-array><string-array translatable="false" name="radioAttributes"><item>"wifi,1,1"</item><item>"mobile,0,1"</item></string-array>ConnectivityManager定義了向對應的字符串常量:public static final int TYPE_MOBILE = 0;/*** The Default WIFI data connection. When active, all data traffic* will use this connection by default. Should not coexist with other* default connections.*/public static final int TYPE_WIFI = 1;/*** An MMS-specific Mobile data connection. This connection may be the* same as {@link #TYPEMOBILE} but it may be different. This is used* by applications needing to talk to the carrier's Multimedia Messaging* Service servers. It may coexist with default data connections.* {@hide}*/public static final int TYPE_MOBILE_MMS = 2;/*** A SUPL-specific Mobile data connection. This connection may be the* same as {@link #TYPEMOBILE} but it may be different. This is used* by applications needing to talk to the carrier's Secure User Plane* Location servers for help locating the device. It may coexist with* default data connections.* {@hide}*/public static final int TYPE_MOBILE_SUPL = 3;/*** A DUN-specific Mobile data connection. This connection may be the* same as {@link #TYPEMOBILE} but it may be different. This is used* by applicaitons performing a Dial Up Networking bridge so that* the carrier is aware of DUN traffic. It may coexist with default data* connections.* {@hide}*/public static final int TYPE_MOBILE_DUN = 4;/*** A High Priority Mobile data connection. This connection is typically* the same as {@link #TYPEMOBILE} but the routing setup is different.* Only requesting processes will have access to the Mobile DNS servers* and only IP's explicitly requested via {@link #requestRouteToHost}* will route over this interface.*{@hide}*/public static final int TYPE_MOBILE_HIPRI = 5;/** {@hide} */public static final int MAX_RADIO_TYPE = TYPE_WIFI;/** {@hide} */public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI;public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;並設置了默認的網絡鏈接是TYPE_WIFI.ConnectivityManager的方法是經過AIDL的使用,調用ConnectivityService中的方法來實現的。ConnectivityService繼承了IConnectivityManage.stub.在ConnectivityService內部,定義了兩個類來解析xml中的網絡類型,類的代碼以下:private class NetworkAttributes {/*** Class for holding settings read from resources.*/public String mName;public int mType;public int mRadio;public int mPriority;public NetworkInfo.State mLastState;public NetworkAttributes(String init) {String fragments[] = init.split(",");mName = fragments[0].toLowerCase();if (fragments[1].toLowerCase().equals("wifi")) {mRadio = ConnectivityManager.TYPE_WIFI;} else {mRadio = ConnectivityManager.TYPE_MOBILE;}if (mName.equals("default")) {mType = mRadio;} else if (mName.equals("mms")) {mType = ConnectivityManager.TYPE_MOBILE_MMS;} else if (mName.equals("supl")) {mType = ConnectivityManager.TYPE_MOBILE_SUPL;} else if (mName.equals("dun")) {mType = ConnectivityManager.TYPE_MOBILE_DUN;} else if (mName.equals("hipri")) {mType = ConnectivityManager.TYPE_MOBILE_HIPRI;}mPriority = Integer.parseInt(fragments[2]);mLastState = NetworkInfo.State.UNKNOWN;}public boolean isDefault() {return (mType == mRadio);}}private class RadioAttributes {public String mName;public int mPriority;public int mSimultaneity;public int mType;public RadioAttributes(String init) {String fragments[] = init.split(",");mName = fragments[0].toLowerCase();mPriority = Integer.parseInt(fragments[1]);mSimultaneity = Integer.parseInt(fragments[2]);if (mName.equals("wifi")) {mType = ConnectivityManager.TYPE_WIFI;} else {mType = ConnectivityManager.TYPE_MOBILE;}}}並經過一下代碼,來給網絡分配優先級,mPriorityList = new int[naStrings.length];{int priority = 0; //lowestint nextPos = naStrings.length-1;while (nextPos>-1) {for (int i = 0; i < mNetAttributes.length; i++) {if(mNetAttributes[i].mPriority == priority) {mPriorityList[nextPos--] = i;}}priority++;}}mNetRequestersPids =new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1];for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) {mNetRequestersPids[i] = new ArrayList();}其中,TYPE_MOBILE_HIPRI的優先級最高,其次爲TYPE_MOBILE_MMS,TYPE_MOBILE_SUPL,TYPE_MOBILE_DUN,優先級最低的爲TYPE_WIFI,TYPE_MOBILE。TYPE_WIFI,TYPE_MOBILE兩個網絡類型中,TYPE_WIFI大於TYPE_MOBILE的優先級,在打開wifi的鏈接後,mobile網絡會被關閉。wifi網絡鏈接關閉後,mobile網絡會從新鏈接。在處理網絡鏈接的Handler的代碼中有處理:private void handleConnect(NetworkInfo info) {int type = info.getType();Log.d(TAG, "Got Network Connection Succ from Driver nwtype="+type);// snapshot isFailover, because sendConnectedBroadcast() resets itboolean isFailover = info.isFailover();NetworkStateTracker thisNet = mNetTrackers[type];// if this is a default net and other default is running// kill the one not preferredif (mNetAttributes[type].isDefault()) {if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {if ((type != mNetworkPreference &&mNetAttributes[mActiveDefaultNetwork].mPriority >mNetAttributes[type].mPriority) ||mNetworkPreference == mActiveDefaultNetwork) {if(!((SystemProperties.get(CNE.UseCne,"false").equals("true") ||SystemProperties.get(CNE.UseCne,"false").equals("TRUE"))&&CNE.isCndUp)) {// don't accept this oneif (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " +"to torn down network " + info.getTypeName());teardown(thisNet);}return;} else {// tear down the otherNetworkStateTracker otherNet =mNetTrackers[mActiveDefaultNetwork];if (DBG) Log.v(TAG, "Policy requires " +otherNet.getNetworkInfo().getTypeName() +" teardown");if(!((SystemProperties.get(CNE.UseCne,"false").equals("true") ||SystemProperties.get(CNE.UseCne,"false").equals("TRUE"))&&CNE.isCndUp)) {if (DBG) Log.i(TAG, "CNE To support Simultaneous Nws we"+" will not tear down other nw");if (!teardown(otherNet)) {Log.e(TAG, "Network declined teardown request");return;}}if (isFailover) {otherNet.releaseWakeLock();}}}mActiveDefaultNetwork = type;}thisNet.setTeardownRequested(false);thisNet.updateNetworkSettings();handleConnectivityChange();sendConnectedBroadcast(info);}SystemServer啓動ConnectivityService,ConnectivityService啓動對網絡的監視器。在SystemServer的run()函數中,啓動ConnectivityService的代碼:try {Log.i(TAG, "Connectivity Service");connectivity = ConnectivityService.getInstance(context);ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);connectivity.startCne();} catch (Throwable e) {Log.e(TAG, "Failure starting Connectivity Service", e);}在ConnectivityService的構造函數中啓動網絡監視器的代碼:if (DBG) Log.v(TAG, "Starting Wifi Service.");WifiStateTracker wst = new WifiStateTracker(context, mHandler);WifiService wifiService = new WifiService(context, wst);ServiceManager.addService(Context.WIFI_SERVICE, wifiService);mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;mNetTrackers[ConnectivityManager.TYPE_MOBILE] =new MobileDataStateTracker(context, mHandler,ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT,"MOBILE");mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] =new MobileDataStateTracker(context, mHandler,ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS,"MOBILE_MMS");mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] =new MobileDataStateTracker(context, mHandler,ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL,"MOBILE_SUPL");mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] =new MobileDataStateTracker(context, mHandler,ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN,"MOBILE_DUN");mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] =new MobileDataStateTracker(context, mHandler,ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI,"MOBILE_HIPRI");mNumDnsEntries = 0;mTestMode = SystemProperties.get("cm.test.mode").equals("true")&& SystemProperties.get("ro.build.type").equals("eng");for (NetworkStateTracker t : mNetTrackers)t.startMonitoring();// Constructing this starts it toomWifiWatchdogService = new WifiWatchdogService(context, wst);在settings中能夠設置網絡鏈接,好比打開wifi,打開bluetooth,設置apn的鏈接等等,在設置完成後,設置的消息會存在一個數據庫中保存,併發送系統消息來廣播網絡設置的變化。在網絡監視器中捕捉了settings中發出的相應的網絡廣播信息,網絡監視器中註冊了settings中網絡變化的信息,有變化會作相應的處理,並將處理的結果存儲在NetworkInfo類的一個對象中,在ConnectivityService中經過public NetworkInfo getNetworkInfo(int networkType)方法能夠得知當前networkType類型網絡的鏈接狀況。在app中,咱們能夠經過ConnectivityManager來獲取當前的網絡信息,並能指定當前程序須要的網絡類型:ConnectivityManager mCnn = context.getSystemService(context.NONNECTIVITY_SERVICE);NetworkInfo mNetinfo = mCnn.getActiveNetworkInfo();mCnn.setNetworkPreference(int preference);//設定首選網絡類型。假如沒有設定,網絡類型爲系統默認。在wifi,3G網絡同時存在的狀況下,系統會默認的調用wifi網絡,加載wifi的驅動,走wifi網絡。

相關文章
相關標籤/搜索