http://blog.sina.com.cn/s/blog_13146f9590101wjhw.html
【摘要】
本文從用戶界面出發,從應用層到硬件適配層,對Android平臺wifi啓動和關閉的流程進行了分析。具體包括wifi模塊初始化、APP層代碼分析、Framework層代碼分析、JNI層代碼分析、HAL層代碼分析、WPA_SUPPLICANT啓動分析,並在分析基礎上對代碼流程進行了總結。
【關鍵詞】
Android WIFI 啓動分析
1 WIFI模塊初始化分析
在分析wifi模塊代碼前,必須需要知道系統在何時對wifi做了初始化,初始化了wifi的哪些類或服務。
Android系統啓動的流程概述如下:
系統引導bootloader->加載內核Kernel->啓動init進程->啓動ServiceManager->Zygote進程->SystemServer。
Android系統中所有服務循環框架均建立在SystemServer上,例如:音頻服務、牆紙管理服務、垃圾箱服務、USB服務、語音識別服務等。SystemServer對應的源文件路徑爲\frameworks\base\services\java\com\android\server\SystemServer.java,其代碼中與wifi模塊相關的片段爲:
try {
Slog.i(TAG, "Connectivity Service");
connectivity = ConnectivityService.getInstance(context);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE,connectivity);
}
catch (Throwable e){
Slog.e(TAG, "Failure starting Connectivity Service", e);
}
上述代碼中通過ServiceManager.addService的方式啓動了ConnectivityService服務。
在ConnectivityService.java(\frameworks\base\services\java\com\android\server)文件中ConnectivityService的構造函數會創建WifiService,代碼片段爲:
switch (mNetAttributes[netType].mRadio) {
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context,mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE,wifiService);
wifiService.startWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();
break;
上述代碼中創建了WifiStateTracker對象和WifiService對象。在wifi模塊中,WifiStateTracker會創建WifiMonitor接收來自底層wpa_supplicant的事件;WifiService負責啓動和關閉wpa_supplicant、把命令下發給wpa_supplicant。至此,完成wifi功能的初始化。
2 WIFI模塊APP層代碼分析
作爲測試人員,一般最熟悉的是用戶界面層面,因此,接下來從上層到底層逐步分析深入,用戶界面對應的代碼是wifi模塊APP層,其代碼位置爲\packages\apps\Settings\src
\com\android\settings\wifi目錄。
Wifi模塊處於settings模塊中,因此,首先定位至:\packages\apps\Settings\src\com\
android\settings目錄,該目錄中和wifi相關的文件有文件夾“wifi”和java源文件WirelessSettings.java。其中WirelessSettings.java文件實現了無線和網絡設置的Activity,其定義如下:
public class WirelessSettingsextends PreferenceActivity{…}
該Activity繼承自PreferenceActivity,PreferenceActivity類是Android中專門用來實現程序設置界面及參數存儲的一個Activity,在設置模塊中基本所有Activity均繼承自此類。
WirelessSettings類的佈局文件通過addPreferencesFromResource(R.xml.wireless_se-
ttings);這段代碼實現。
因此,接下來需要分析wireless_settings.xml,定位到:\packages\apps\Settings\res\xml文件夾找到wireless_settings.xml文件。該佈局文件部分代碼如下:
android:key="toggle_wifi"
android:title="@string/wifi_quick_toggle_title"
android:summary="@string/wifi_quick_toggle_summary"
android:persistent="false" />
android:key="wifi_settings"
android:title="@string/wifi_settings"
android:summary="@string/wifi_settings_summary" >
android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.wifi.WifiSettings"/>
……
該佈局文件使用了PreferenceScreen、CheckBoxPreference等組件,這些組件是PreferenceActivity的幾種組件,總結介紹如下:
PreferenceScreen:設置頁面,可嵌套形成二級設置頁面,用Title參數設置標題。
PreferenceCategory:某一類相關的設置,可用Title參數設置標題。
CheckBoxPreference:是一個CheckBox設置,只有兩種值,true或false,可用Title參數設置標題,用summaryOn和summaryOff參數來設置控件選中和未選中時的提示。
ListPreference:下拉框選擇控件,用Title參數設置標題,用Summary參數設置說明,點擊後出現下拉框,用dialogTitle設置下拉框的標題,下拉框內顯示的內容和具體的值需要在res/values/array.xml中設置兩個array來表示。
上述各種組件的顯示舉例如圖1所示:
圖1 PreferenceActivity的幾種控件
在wireless_settings.xml文件中,wifi相關的控件爲CheckBoxPreferenceandroid:key="toggle_wifi"和。基於此,在WirelessSettings.java文件中找到對應的控件操作方法:
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wireless_settings);
CheckBoxPreferencewifi=(CheckBoxPreference)findPreference(KEY_TOGGLE_WIFI);
mWifiEnabler = newWifiEnabler(this, wifi);
……
可以看出,在WirelessSettings的onCreate方法中生成一個WifiEnabler對象,具體的wifi狀態的控制交給WifiEnabler類。
在WifiEnabler類的構造函數中使用mWifiManager =(WifiManager)context.getSystemService(Context.WIFI_SERVICE); 這段代碼獲得WifiManager類對象,並在CheckBox的事件響應函數中使用mWifiManager.setWifiEnabled(enable) 來wifi進行開啓和關閉,相關代碼如下:
publicWifiEnabler(Context context, CheckBoxPreference checkBox){
mWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
……
}
publicboolean onPreferenceChange(Preference preference, Object value){
……
mWifiManager.setWifiEnabled(enable);
……
}
3 WIFI模塊Framework層代碼分析
根據APP層的分析結果,接下來需要跟蹤分析WifiManager類,該文件存放路徑爲:\frameworks\base\wifi\java\android\net\wifi,這個目錄下存放的是wifi模塊framework層的代碼文件。
WifiManager類中setWifiEnabled方法的定義如下:
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(enabled);
} catch (RemoteException e) {
return false;
}
}
上面代碼中使用mService對象的setWifiEnabled方法,查看WifiManager的構造函數
public WifiManager(IWifiManager service, Handler handler){
mService = service;
mHandler = handler;
}
得知:mService是IWifiManager類型對象引用。查看源碼目錄\frameworks\base\wifi\java\android\net\wifi,存在有IWifiManager.aidl文件。實際上,在Android中AIDL的作用是實現對遠程服務的調用。IWifiManager是對遠程服務WifiService進行了調用,調用IWifiManager的setWifiEnabled()方法實際是調用WifiService的setWifiEnabled()方法
WifiService.java的存放路徑爲\frameworks\base\services\java\com\android\server。其setWifiEnabled方法的實現代碼如下:
public booleansetWifiEnabled(boolean enable) {
enforceChangePermission();
if (mWifiHandler == null) return false;
synchronized (mWifiHandler) {
// caller may not have WAKE_LOCK permission - it's not requiredhere
long ident = Binder.clearCallingIdentity();
sWakeLock.acquire();
Binder.restoreCallingIdentity(ident);
mLastEnableUid = Binder.getCallingUid();
// set a flag if the user is enabling Wifi while in airplanemode
mAirplaneModeOverwridden = (enable && isAirplaneModeOn()&& isAirplaneToggleable());
sendEnableMessage(enable, true, Binder.getCallingUid());
}
return true;
}
在上述代碼中,通過sendEnableMessage發送消息處理wifi打開和關閉動作。在WifiService.java中sendEnableMessage方法的實現爲:
private void sendEnableMessage(boolean enable, boolean persist, intuid) {
Message msg = Message.obtain(mWifiHandler,
(enable ? MESSAGE_ENABLE_WIFI :MESSAGE_DISABLE_WIFI),(persist ? 1 : 0), uid);
msg.sendToTarget();
}
可以看出,WifiService最終是生成一個wifi開啓或關閉的消息,並將消息發送至自己的消息隊列,由WifiService類的handleMessage方法處理消息。handleMessage中的部分代碼如下:
publicvoid handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
if (mWifiWatchdogService == null) {
mWifiWatchdogService = new WifiWatchdogService(mContext,mWifiStateTracker);
}
sWakeLock.release();
break;
caseMESSAGE_DISABLE_WIFI:
// a non-zero msg.arg1 value means the "enabled" setting
// should be persisted
setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
mWifiWatchdogService = null;
sWakeLock.release();
break;
……
在WifiService.java文件中跟蹤代碼中setWifiEnabledBlocking方法:
private boolean setWifiEnabledBlocking(boolean enable,boolean persist, int uid) {
…….
if(enable) {
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
……
if(!mWifiStateTracker.unloadDriver()) {
Slog.e(TAG, "Failed to unload Wi-Fi driver.");
if (!failedToStopSupplicantOrUnloadDriver) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
failedToStopSupplicantOrUnloadDriver = true;
}
}
……
在該方法中使用mWifiStateTracker.loadDriver()和mWifiStateTracker.unloadDriver();實現wifi驅動的加載和卸載。
跟蹤代碼得知mWifiStateTracker爲WifiStateTracker類型對象引用,在之前分析wifi初始化時已經得知WifiStateTracker在系統啓動時已經由ConnectivityService生成,此時對驅動進行加載和卸載時可以直接使用WifiStateTracker的對象引用實現操作。
WifiStateTracker類的源碼(文件位置\frameworks\base\wifi\java\android\net\wifi),代碼片段如下:
public synchronized boolean loadDriver() {
return WifiNative.loadDriver();
}
public synchronized boolean unloadDriver() {
return WifiNative.unloadDriver();
}
因此,需要跟蹤WifiNative(文件位置\frameworks\base\wifi\java\android\net\wifi)的代碼,片段如下:
public native static boolean loadDriver();
public native staticboolean unloadDriver();
可以看出,WifiNative通過JNI的方式調用底層的cpp代碼實現wifi使能管理。