Android平台WIFI启动流程之二
http://blog.sina.com.cn/s/blog_13146f9590101wji1.html
【摘要】
本文从用户界面出发,从应用层到硬件适配层,对Android平台wifi启动和关闭的流程进行了分析。具体包括wifi模块初始化、APP层代码分析、Framework层代码分析、JNI层代码分析、HAL层代码分析、WPA_SUPPLICANT启动分析,并在分析基础上对代码流程进行了总结。
【关键词】
Android WIFI 启动分析
1 WIFI模块JNI层代码分析
Android中以JNI的方式实现java代码对C代码的调用。接下来跟踪wifi模块JNIcpp文件的实现,在目录\frameworks\base\core\jni中存放了android的JNI 本地实现文件,这些文件在编译后会生成libandroid_runtime.so库文件并存放于手机/system/lib目录下。其中与wifi模块相关的android_net_wifi_Wifi.cpp文件的代码片段如下:
#include "wifi.h"
staticjboolean android_net_wifi_loadDriver(JNIEnv* env, jobjectclazz)
{
return (jboolean)(::wifi_load_driver() == 0);
}
staticjboolean android_net_wifi_unloadDriver(JNIEnv* env, jobjectclazz)
{
return (jboolean)(::wifi_unload_driver() == 0);
}
在WifiNative.java中loadDriver()和unloadDriver()对应的cpp函数实现分别是android_net_wifi_Wifi.cpp文件中android_net_wifi_loadDriver和android_net_wifi_unloadDriver两个函数。android_net_wifi_Wifi.cpp中包含#include"wifi.h",且两个函数中分别使用了wifi_load_driver()、wifi_unload_driver()两个函数。实际上,在android_net_wifi_Wifi.cpp是对底层适配层的代码封装,具体的操作通过调用底层代码实现。
2 WIFI模块HAL层代码分析
根据JNI层代码实现得知,HAL层实现文件与wifi.h对应,因此,接下来需要分析wifi.c文件(文件位置:\hardware\libhardware_legacy\wifi,HAL层代码存放位置),wifi.c文件的代码片段如下:
#ifndef WIFI_DRIVER_MODULE_PATH
#defineWIFI_DRIVER_MODULE_PATH "/system/lib/modules/wlan.ko"
#endif
……
intwifi_load_driver()
{
……
if(insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
return -1;
……
}
intwifi_unload_driver()
{
…….
if(rmmod(DRIVER_MODULE_NAME) == 0)
……
}
staticint insmod(const char *filename, const char *args)
{
……
module = load_file(filename, &size);
……
}
staticint rmmod(const char *modname)
{
……
ret = delete_module(modname,O_NONBLOCK | O_EXCL);
……
}
其中,DRIVER_MODULE_PATH宏表示wifi驱动文件的路径,其值为"/system/lib/modules/wlan.ko",这个路径表示手机中wifi内核驱动文件所存放的路径,wlan.ko是wifi驱动源文件经过编译后的内核驱动文件,在不同平台和厂商的手机中这个文件的文件名称和存放路径是不一样的。比如marvel平台960s手机中wlan模块的驱动文件的存放路径和文件名为:/system/lib/modules/mlan.ko和/system/lib/modules/sd8787.ko。
在android内核原生代码中,wlan模块驱动源文件存放路径为“\drivers\net\wireless”,这些文件经过编译后会生成.ko后缀的驱动文件并存放在手机中。在不同平台手机中,驱动的源代码存放位置会有所不同,源代码内容会有所不同,因此,对于驱动源码的分析需要针对具体的平台,本文仅根据原生代码分析,此处不涉及驱动源码分析。
至此,完成从APP层到驱动适配层的分析跟踪,wifi模块完成驱动加载和卸载。
3 WIFI模块WPA_SUPPLICANT启动分析
wpa_supplicant是wpa的应用层认证客户端,负责完成认证相关的工作,开启wifi功能除了需要加载驱动外,还需要启动wpa_supplicant程序。
wpa_supplicant的源码路径为:\external\wpa_supplicant
该路径下的源码经过编译后生成的主要文件是库文件libwpa_client.so和可执行文件wpa_supplicant。在marvel960s手机中,这两个文件分别为/system/lib/libwpa_client.so和/system/bin/wpa_supplicant。
下面根据驱动加载过程的分析方法,对wpa_supplicant的启动和关闭流程进行分析:
在framework层,WifiService.java文件的setWifiEnabledBlocking函数中除了执行了加载驱动动作,还执行了启动wpa_supplicant的动作。如下:
private boolean setWifiEnabledBlocking(boolean enable,boolean persist, int uid) {
…….
if(enable) {
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
mWifiStateTracker.startSupplicant()的作用是启动wpa_supplicant。根据上面的方法跟踪代码如下:
framework层WifiStateTracker.java中:
public synchronized boolean startSupplicant() {
return WifiNative.startSupplicant();
}
public synchronized boolean stopSupplicant() {
return WifiNative.stopSupplicant();
}
framework层WifiNative.java中:
publicnative static boolean startSupplicant();
publicnative static boolean stopSupplicant();
JNI层android_net_wifi_Wifi.cpp中:
staticjboolean android_net_wifi_startSupplicant(JNIEnv* env, jobjectclazz)
{
return (jboolean)(::wifi_start_supplicant() == 0);
}
staticjboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobjectclazz)
{
return (jboolean)(::wifi_stop_supplicant() == 0);
}
HAL层wifi.c文件中:
staticconst charIFACE_DIR[] = "/data/system/wpa_supplicant";
staticconst char SUPP_CONFIG_TEMPLATE[]="/system/etc/wifi/wpa_supplicant.conf";
staticconst charSUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf";
staticconst charSUPPLICANT_NAME[] = "wpa_supplicant";
intwifi_start_supplicant()
{
……
ensure_config_file_exists();
property_set("ctl.start", SUPPLICANT_NAME);
……
}
intwifi_stop_supplicant()
{
……
property_set("ctl.stop", SUPPLICANT_NAME);
……
}
intensure_config_file_exists()
{
……
access(SUPP_CONFIG_FILE, R_OK|W_OK)
srcfd= open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
destfd= open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
……
}
wifi.c文件中的字符串常量指明了wpa_supplicant程序及wpa_supplicant配置文件在手机中的存放位置("/data/system/wpa_supplicant"和"/data/misc/wifi/wpa_supplicant.conf"),并通过intensure_config_file_exists()、wifi_start_supplicant()、wifi_stop_supplicant()等函数实现配置文件的加载和wpa_supplicant程序的启动关闭。
wpa_supplicant启动之后,操作系统启动时生成的WifiMonitor和WifiService对象就可以与之通信实现wifi的一系列操作。
4 WIFI模块启动流程总结
根据上述分析结果,下面将WIFI功能启动流程总结如下,如图2所示(需放大3倍查看)。
图1 WIFI启动流程