Android平臺WIFI啓動流程之一

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所示:

#Android#Android平臺WIFI啓動流程之一

圖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使能管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章