Android WIFI系统引入了wpa_supplicant,它的整个WIFI系统以wpa_supplicant为核心来定义上层接口和下层驱动接口。Android WIFI主要分为六大层,分别是WiFi Settings层,Wifi Framework层,Wifi JNI 层, Wifi HardWare 层, Wpa_supplicant 层和 Wifi Kernel 层。
Wifi Settings层 ------> Java应用层
Wifi Framework层 ------> Java框架层
Wifi JNI层 ------> C框架层
Wifi HardWare层 ------> C框架层
Wpa_supplicant层 ------> C框架层
Wifi Kernel层 ------> 内核空间
下面对上图的部分做出分析:
1.1 Wifi Service
由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及更新WIFI的状态。处理其它模块通过WifiManager接口发送过来的远端WiFi操作。
1.2 WifiMonitor
负责从wpa_supplicant接收事件通知。
1.3 wpa_supplicant
1)读取配置文件
2)初始化配置参数
3)让驱动scan当前所有的bssid
4)检查扫描的参数是否和用户设置的相符
5)如果相符,通知驱动进行权限和认证操作
6)连上AP
注意:
AP(Access Point),也就是无线接入点,是一个无线网络的创建者,是网络的中心节点,俗称“热点”。无线网络中的无线交换机,它是使用无线设备(手机等移动设备和笔记本电脑等无线设备)用户进入有线网络的接入点。大多数无线AP还带有接入点客户端模式(AP client),可以和其它AP进行无线连接,延展网络的覆盖范围。
1.4 Wifi 驱动模块
厂商提供的source,主要进行load firware和kernel的wireless进行通信
1.5 Wifi 电源管理模块
主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口或者USB接口通信。
1.6 Wifi 工作步骤
1)Wifi 启动
2)开始扫描
3)显示扫描的AP
4)配置AP
5)连接AP
6)获取IP地址
7)上网
1. Wifi Settings层
//代码目录
packages/apps/Settings/src/com/android/settings/wifi/
主要的类:
WifiSettings.java : 负责显示 Wifi 的设置界面
WifiEnabler.java : 负责 Wifi 的开关逻辑
WifiDialog.java : 负责Wifi的对话框
WifiDInfo.java : 表示Wifi 的相关配置信息
2. Wifi Framework 层
//代码目录
frameworks/base/wifi/Java/android/net/wifi/
frameworks/base/core/java/android/net/
frameworks/opt/net/wifi/service/java/com/android/server/wifi
主要的类:
WifiManager : 它是 Wifi 模块向外部应用透漏出来的接口,其它所有应用都可以通过WiFi Manager 来操作Wifi 的各项功能,当时WifiManager 本身不具备处理请求的能力,而是把所有的请求转发给WifiServicelmpl 来处理。
WifiService : Java Framework中 Wifi 功能的总入口,负责 Wifi 功能的核心业务。它是服务器端的实现,作为 Wifi 部分的核心,处理实际的驱动加载、扫描、链接、断开等命令,以及底层上报的事件。对于主动的命令控制,Wifi 是一个简单的封装,针对来自客户端的控制命令,调用相应的WifiNative底层实现。
WifiServicelmpl : 本身也不具备处理请求的能力,而是将请求分类后交给不同的处理者处理,比如WifiStateMachine。
WifiStateMachine : 它是一个复杂的状态机,维护了Wifi的启动、扫描、连接、断开等多个状态。它运行自己独有的线程中,拥有自己的消息队列。
WifiState Tracker : 除了负责Wifi 的电源管理模式等功能外,其核心是WifiMonitor所实现的事件轮询机制,以及消息处理函数handleMessage()。
WifiMonitor : 专门负责接收来自wpa_supplicant的事件,并将这些信息进行分类再交予StateMachine处理。
WifiNative :一个接口类,主要是提供一些native方法用于wifi framework层和 WPAS 通信。WifiNative 的主要实现都在 wifi.c 函数里,WifiNative 仅是将其封装,给framework层调用。
注意:WifiService 和 WifiMonitor 是整个模块的核心。WifiService 负责启动关闭wpa_supplicant,启动关闭WifiMonitor监视线程和把命令下发给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接收事件通知。
也就是说Wifiservice负责wifi整个流程的控制,而WifiMonitor负责监视底层的事件。
3. Wifi JNI 层
//代码目录
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
android_net_wifi_Wifi.cpp就是典型jni接口,通过它可以直接调用Wifi的硬件抽象层。
4. Wifi Hardware 层(wifi管理库)
//代码目录
hardware/libhardware_legacy/wifi/wifi.c
Wifi Hardware 层也被称为wpa_supplicant适配层,是通用wpa_supplicant的封装。wpa_supplicant适配层起着承上启下的作用,主要用于和wpa_supplicant守护进程的通信,以供给Wifi框架层使用。
5. wpa_supplicant层(wifi tool)
//代码目录
external/wpa_supplicant/
wpa_supplicant是一个开源项目,已经移植到Linux、Windows以及其它嵌入式系统上。它是WPA(WiFi Protected Access,Wifi 网络安全存取)的应用层认证客户端,负责完成认证相关的登录、加密等工作。该层是Wifi Framework层的基石,也叫Wifi 服务层。
经过编译后主要结果是生成动态库libwpa_client.so和可执行程序wpa_supplicant。
1)wpa_client (生成库libwpaclient.so)
external/wpa_supplicant_8/wpa_supplicant/src/common/wpa_ctrl.c
2) wpa_server (生成守护进程wpa_supplicant)
external/wpa_supplicant_8/wpa_supplicant/main.c
6. Wifi Kernel 层
//代码目录
kernel/drivers/net/wireless
kernel/drivers/wlan_sd8688
arch/arm/mach-pxa/wlan_pm.c
图 3.1 WifiService 和 wpa_supplicant启动流程
状态变化
加载wifi驱动的状态变化流程如下:
mInitialState(初始状态)
|
mDriverUnloadedState
|
mWaitForP2pDisableState
|
mDriverLoadingState(其enter中调用WifiNative.loadDriver)
启动wpa_supplicant的状态变化如下:
在DriverLoadedState状态的processMessage中调用WifiNative.startSupplicant
生产时自动打开Wifi
在生产时, 默认Wifi是关闭的,如果需要默认打开,可修改wifiservice.java中的如下代码:
/**
* Check if Wi-Fi needs to be enabled and start
* if needed
*
* This function is used only at boot time
*/
public void checkAndStartWifi() {
mAirplaneModeOn.set(isAirplaneModeOn());
mPersistWifiState.set(getPersistedWifiState());
/* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled); //强制设置为true
mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
makeWifiWatchdogStateMachine(mContext);
}
wpa_supplicant是一个开源软件源项目,它实现了Station对无线网络进行管理和控制的功能。wpa_supplicant支持的功能非常多,下面列举几个重要的功能。
1)支持WPA—PSK(WPA-Personal)和WPA-Enterprise(利用RAIDUS认证服务器来完成身份认证的情况)
2)数据加密方面支持CCMP,TKIP,WEP104和WER40。其中,WEP104和WEP40中的数字代表密钥的长度。
3)完全支持WPA和WPA2,包括PMKSA缓存,预认证(pre-authentication)等功能
4)完全支持IEEE 802.11r和802.11w,其中802.11r规范定义了快速基础服务转移功能,而802.11w新增对了对管理帧的安全保护机制。
5)支持WFA制定的WIFI protected Setup功能,P2P,TDLS等。
支持多种EAP Method。
主要和802.1X中的Supplicant的功能有关,wpa_supplicant支持多达25种EAP Method,包括以下EAP-TLS,EAP-PEAP,EAP-TTLS和EAP-SIM、EAP-PSK、EAP-GPSK等其他认证方法。
对各种无线网卡和驱动的支持。
1)支持nl80211/cfg80211驱动和Linux Wireless Extension驱动。
2)支持Windows平台中的NDIS驱动。
wpa_supplicant包含三个主要子目录,如下:
1)hostapd:当手机进入Soft AP模式时,手机扮演AP的角色,需要hostapd来提供AP功能。
2)wpa_supplicant:Station模式,也叫Managed模式(重点)
3)src:hostapd和wpa_supplicant中都包含了一些通用的数据结构和处理方法,这些内容都放在src目录中。
wpa_supplicant是Android用户空间中无线网络部分的核心模块,所有Framework层中和WIFI相关的操作最终都由wpa_supplicant来完成。
wpa_supplicant是比较庞大的开源软件项目,内部模块结构如图:
1)WPAS所有工作都围绕事件(event loop模块)展开,它是基于事件驱动的。事件驱动和消息驱动类似,主线程等待事件的发生并处理它们。
2)位于event loop模块下方的driver interface接口模块用于隔离和底层驱动直接交互的那些driver控制模块(wext、ndiswrapper等,WPAS中称为driver wrapper)
3)dirver wrapper经常返回一些信息给上层。
WPAS对外通过控制接口模块与客户端通信。在Android平台中,WPAS的客户端是位于Framework中的WifiService。用户在Settings界面进行WiFi相关的操作最终都会经由WifiService通过发送命令的方式转交给wpa_supplicant去执行。
1. 命令
WPAS定义了许多命令。
PING:心跳检测命令。客户端用它判断WPAS是否工作正常。WPAS收到"PING"命令后需要回复"PONG"。
MIB:客户端用该命令获取设备的MIB信息。
STATUS:客户端用该命令获取设备的MIB信息。
ADD_NETWORK:为WPAS添加一个新的无线网络。它将返回此新无线网络的ID
SET_NETWORK:network id是无线网络的ID。此命令用于设置指定无线网络的信息。其中variable为参数名,value为参数的值。
ENABLE_NETWORK: 使能某个无线网络。此命令最终将促使WPAS发起一系列操作以加入该无线网络。
除了接收来自client的命令外,WPAS也会主动给client发送命令。
2. 控制API
Android平台中wifiService是WPAS的客户端,它和WPAS交互时必须使用wpa_supplicant提供的API。这些API声明于wpa_ctrl.h中,用法如下:
//必须包含此头文件,链接时需要包含libwpa_client.so动态库。
#include "wpa_ctrl.h"
客户端使用wpa_ctrl时首先要分配控制对象。下面两个API用于创建和销毁控制对象wpa_ctrl。
//创建一个wpa控制端对象wpa_ctrl。Android平台中,参数ctrl——path代表unix域socket的位置
struct wpa_ctrl *wpa_ctrl_open(const char *ctrl_path);
//注销wpa_ctrl控制对象
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
下面这个函数用于发送命令给WAPS。
//客户端发送命令给wpa_supplicant,回复的消息保存在reply中
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len));
msg_cb是一个回调函数,该参数的设置和WPAS中C/S通信机制的设计有关。
打开通知事件监听功能相关的API如下所示。
//打开通知事件功能
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
//打开通知事件监听功能的wpa_ctrl对象能直接调用下面的函数来接收unsolicited event
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
如果客户端并不发送命令,而只是想接收Unsolicited event,可通过wpa_ctrl_recv函数来此达到目的。
综上所述,单独使用wpa_ctrl_recv和wpa_ctrl_request都不方便。因此,常用的方法是:客户端创建两个wpa_ctrl对象来简化自己的逻辑处理。
1)一个打开了通知事件监听功能的wpa_ctrl对象将只通过wpa_ctrl_recv来接收通知事件。
2)另外一个wpa_ctrl专职用于发送命令和接收回复。由于没有调用wpa_ctrl_attach,所以它不会收到通知事件。
通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使手机加入一个利WPA_PSK进行认证的无线网络。
dhcpcd成功执行后,手机将从AP那边分配到一个IP地址。至此,手机就可以使用"Tes" 无线网络。
综上所述,所有来自客户端的命令都由wpa_supplicant_ctrl_iface_receive函数处理;绝大部分命令都由wpa_supplicant_ctrl_iface_process函数处理。
ENABLE_NETWORK命令处理
ENABLE_NETWORK命令由wpa_supplicant_ctrl_iface_enable_network进行处理,其代码如下:
wpa_supplicant_scan是无线网络扫描的核心函数,其代码比较复杂,分段来分析。
1)wpa_supplicant_scan分析之一
这一段的代码主要和scan请求的参数准备有关。
一个Probe Request要么指定wildcard ssid以扫描周围所有的无线网络,要么指定某个ssid以扫描指定无限网络。为了方便WPAS的使用,wlan driver新增一个功能,使得上层可通过一次scan请求来扫描多个不同ssid的无线网络。一个scan请求在代码中对应的数据结构就是wpa_driver_scan_params。而wpa_supplicant_scan最重要的工作就是准备好这个请求。
2)wpa_supplicant_scan分析之二
接着来看代码段二
上诉wpa_supplicant_scan代码主要展示了如何填写扫描请求参数,复杂的点在于细节处理。
3)wpa_supplicant_scan分析三
当scan请求的参数准备好,wpa_supplicant_scan将直接向driver wrapper发起scan请求。
对driver_nl80211,对应的函数是wpa_driver_nl80211_scan,看下面代码。
本例来说,ENABLE_WORK命令处理的第一步就是要扫描周围的无线网络。至于目标无线网络是否存在,则属于扫描结果处理流程的工作了。
4)无线网络扫描流程总结
下图为触发扫描扫描功能的流程图。
图中的函数,wpa_supplicant_scan的内容较丰富,其中有很多细节内容。初次学习,可先不考虑图中函数的细节,只需把握图中函数调用流程即可。