http://blog.sina.com.cn/s/blog_13146f9590101wjhw.html
【摘要】
本文从用户界面出发,从应用层到硬件适配层,对Android平台wifi启动和关闭的流程进行了分析。具体包括wifi模块初始化、APP层代码分析、Framework层代码分析、JNI层代码分析、HAL层代码分析、WPA_SUPPLICANT启动分析,并在分析基础上对代码流程进行了总结。
【关键词】
Android
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 {
catch (Throwable e){
上述代码中通过ServiceManager.addService的方式启动了ConnectivityService服务。
在ConnectivityService.java(\frameworks\base\services\java\com\android\server)文件中ConnectivityService的构造函数会创建WifiService,代码片段为:
上述代码中创建了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类的布局文件通过addPreferencesFromResour
ttings);这段代码实现。
因此,接下来需要分析wireless_settings.xml,定位到:\packages\apps\Settings\res\xml文件夹找到wireless_settings.xml文件。该布局文件部分代码如下:
……
该布局文件使用了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);
addPreferencesFromResour
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方法的定义如下:
上面代码中使用mService对象的setWifiEnabled方法,查看WifiManager的构造函数
}
得知: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) {
在上述代码中,通过sendEnableMessage发送消息处理wifi打开和关闭动作。在WifiService.java中sendEnableMessage方法的实现为:
Message msg = Message.obtain(mWifiHandler,
可以看出,WifiService最终是生成一个wifi开启或关闭的消息,并将消息发送至自己的消息队列,由WifiService类的handleMessage方法处理消息。handleMessage中的部分代码如下:
publicvoid handleMessage(Message msg) {
caseMESSAGE_DISABLE_WIFI:
private boolean setWifiEnabledBlocking(boolean enable,boolean persist, int uid) {
……
在该方法中使用mWifiStateTracker.loadDriver()和mWifiStateTracker.unloadDriver();实现wifi驱动的加载和卸载。
跟踪代码得知mWifiStateTracker为WifiStateTracker类型对象引用,在之前分析wifi初始化时已经得知WifiStateTracker在系统启动时已经由ConnectivityService生成,此时对驱动进行加载和卸载时可以直接使用WifiStateTracker的对象引用实现操作。
WifiStateTracker类的源码(文件位置\frameworks\base\wifi\java\android\net\wifi),代码片段如下:
因此,需要跟踪WifiNative(文件位置\frameworks\base\wifi\java\android\net\wifi)的代码,片段如下:
public native staticboolean unloadDriver();
可以看出,WifiNative通过JNI的方式调用底层的cpp代码实现wifi使能管理。