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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值