wifi workflow
我把android下的wifi流程分析主要分为三个部分。。一个是开启wifi过程,一个是查找wifi过程,一个是连接wifi过程。下面就具体过程进行分析。
1.开启wifi
android wifi 自上而下包括五个层次。linux内核中的标准wifi驱动程序和协议,Wpa_supplicant可执行程序,wpa_supplicant适配层,wifi的JNI接口,wifi的java框架,wifi的相关应用。下面通过对wifi的开启操作来了解一下wifi的工作流程。
1) 用户在设置界面开启WiFi。调用Settings应用程序的wifiEnabler.setWifiEnabled,然后调用mWifiManager.setWifiEnabled。
private void setWifiEnabled(final boolean enable) {
// Disable button
mWifiCheckBoxPref.setEnabled(false);
if (!mWifiManager.setWifiEnabled(enable)) {
mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping);
}
}
2) mWifiManager.setWifiEnabled通过Binder机制调用WifiService.setWifiEnabled。这里WifiService就是Wifi的java层内容。
public boolean setWifiEnabled(boolean enable) {
enforceChangePermission();
if (mWifiHandler == null) return false;
synchronized (mWifiHandler) {
sWakeLock.acquire();
mLastEnableUid = Binder.getCallingUid();
sendEnableMessage(enable, true, Binder.getCallingUid());
}
return true;
}
3) WifiService.setWifiEnabled将MESSAGE_ENABLE_WIFI消息发送到自己的消息队列。
4) WifiService通过WifiHandler的handleMessage处理MESSAGE_ENALBE_WIFI,调用setWifiEnableBlocking。SetWifiEnalbedBlocking调用setWifiEnabledState,向外发出WIFI_STATE_CHANGED_ACTION通知消息。另外,它还完成一些初始化工作,如设置当前状态、加载WiFi驱动、开启wpa_supplicant、开启WifiStateTracker、注册BroadcastReceive监视WifiStateTracker的消息等。代码如下:
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
if (mWifiState == eventualWifiState) {
return true;
}
if (enable && isAirplaneModeOn()) {
return false;
}
if (!enable && (mWifiState == WIFI_STATE_UNKNOWN))
{
Log.e(TAG, "Wi-Fi is in unknown status , can not be disable");
return false;
}
setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
if (enable) {
if (!WifiNative.loadDriver()) { //调用JNI层,加载WiFi驱动
Log.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
if (!WifiNative.startSupplicant()) { //调用JNI层,启动Supplicant
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
……
4.1)加载wifi驱动流程:进入到WifiNative.loadDriver()中。通过WifiNative发送一个loadDriver消息给jni层。Android_net_wifi_wifi通过一个数组 static JNINativeMethod gWifiMethods[]获得该消息。
static JNINativeMethod gWifiMethods[] = {
/* name, signature, funcPtr */
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
{ "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant },
{ "stopSupplicant", "()Z", (void *)android_net_wifi_stopSupplicant },
{ "connectToSupplicant", "()Z", (void *)android_net_wifi_connectToSupplicant },
{ "closeSupplicantConnection", "()V", (void *)android_net_wifi_closeSupplicantConnection },
……
调用android_net_wifi_loadDriver函数。从而调用wifi_load_driver函数。
接着就要入到wpa_supplicant适配层了。进入到wifi.wifi_load_driver中。在这里设置wifi电压,加载编译的ko模块等。
4.2)开启wpa_supplicant过程:通过WifiNative.startSupplicant,类似加载驱动的方式调用android_net_wifi_startSupplicant,进而调用wifi. wifi_start_supplicant。
5) 由于WifiEnabler初始化时注册了BroadcastReceiver,因此它会获得这个通知消息,进入handleWifiStateChanged处理一些内部状态及显示。
6) WifiLayer也同样获得了这个通知消息,至此,WiFi开启完成。所以就开始查找AP:
private void handleWifiStateChanged(int wifiState) {
if (wifiState == WIFI_STATE_ENABLED) {
loadConfiguredAccessPoints();
attemptScan();
} else if (wifiState == WIFI_STATE_DISABLED) {
removeFutureScans();
if (LOGV) Log.v(TAG, "Clearing AP lists because wifi is disabled");
clearApLists();
}
if (mCallback != null) {
mCallback.onAccessPointsStateChanged(wifiState == WIFI_STATE_ENABLED);
}
}
2.查找AP
1) Settings应用程序的WifiLayer.attemptScan调用WifiManger.startScan。
2) Settings应用程序的WifiManger.startScan通过Binder机制调用WifiService.startScan。
3) WiFi服务层的WifiServiceWifiNative.scanCommand通过WifiNative发送扫描命令给wpa_supplicant,中间经过JNI实现中的doCommand,最终调用wpa_supplicant适配层的wifi_command来完成这一发送过程。至此,命令发送成功。
3.1)详细调用过程:WifiNative发送扫描命令给wpa_supplicant。JNI层获得scanCommand命令,进而调用android_net_wifi_scanCommand函数。
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz)
{
jboolean result;
// Ignore any error from setting the scan mode.
// The scan will still work.
(void)doBooleanCommand("DRIVER SCAN-ACTIVE", "OK");
result = doBooleanCommand("SCAN", "OK");
(void)doBooleanCommand("DRIVER SCAN-PASSIVE", "OK");
return result;
}
进入到doBooleanCommand中,进而调用doCommand函数。在接着调用wifi_command函数。这样就进入到wpa_supplicant适配层了。调用wifi. wifi_command。
4) 命令的最终响应由wap_supplicant上报“SCAN-RESULTS”消息,WifiStateTracker开启的WifiMonitor的MonitorThread可以获取此消息并交由handleEvent处理。
4.1)详细过程如下:wifi.wifi_command实际上是wifi_send_command的封装。进而调用wpa_ctrl_request函数。从而调用wpa_ctrl.wpa_ctrl_request函数。
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))
{
DWORD written;
DWORD readlen = *reply_len;
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
return -1;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
return -1;
*reply_len = readlen;
return 0;
}
继而就将命令发送给了wpa_supplicant。Wpa_supplicant将做进一步的接收。在wpa_supplicant.c中在经过wpa_supplicant_add_iface,wpa_supplicant_init_iface2,wpa_supplicant_ctrl_iface_init。在调用Ctrl_iface_unix. wpa_supplicant_ctrl_iface_init。注册ctrl_conn控制端口和monitor_conn监听端口的处理函数。
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);//ctrl_conn端口的handler处理函数
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);//monitor_conn端口的回调处理函数,处理netlink数据到所有monitor_conn监听端口
4.2)继续调用wpa_supplicant_ctrl_iface_receive函数。在ctrl_iface_unix.c中调用wpa_supplicant_ctrl_iface_process。
4.3)进入到ctrl_iface. wpa_supplicant_ctrl_iface_process中。
else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
reply_len = -1;
调用wpa_supplicant_ctrl_iface_ap_scan函数。
static int wpa_supplicant_ctrl_iface_ap_scan(
struct wpa_supplicant *wpa_s, char *cmd)
{
int ap_scan = atoi(cmd);
if (ap_scan < 0 || ap_scan > 2)
return -1;
wpa_s->conf->ap_scan = ap_scan;
return 0;
}
这样就实现了wpa的扫描。并把扫描命令传给wpa_supplicant了。
4.4)wpa_supplicant上报“SCAN-RESULTS”消息。WifiMonitor启动MonitorThread获得该消息。中间经过一些等待响应事件。最终交给handleEvent处理。
public class WifiMonitor {
……
public void startMonitoring() {
new MonitorThread().start();//启动java线程
}
class MonitorThread extends Thread {
public MonitorThread() {
super("WifiMonitor");
}
public void run() {
……
for (;;) {
String eventStr = WifiNative.waitForEvent();
……
else if (eventName.equals(scanResultsEvent))
event = SCAN_RESULTS;
……
else {
handleEvent(event, eventData);
}
5) handleEvent的处理方式是调用WifiStateTracker.notifyScanResultsAvailable。
6) 在WifiStateTracker中,通过EVENT_SCAN_RESULTS_AVAILABLE完成消息传递,调用sendScanResultsAvailable将SCAN_RESULTS_AVAILABLE_ACTION通知消息广播出去。
7) WifiLayer会最终获得这个通知消息,调用handleScanResultsAvailable继续处理。此函数会根据返回的AP数据建立对应的处理结构,并完成对应界面的绘制,以供用户操作AP 列表。至此,AP查找完成。
3.连接AP
1) 单击AP列表的某个项目后,会弹出AccessPointDialog对话框,单击“连接”按钮,将handleConnect转化为到WifiLayer.connectToNetwork的调用。
2) 在connectToNetwork中完成一些查找和配置,再通过managerEnableNetwork调用WifiManager.enableNetwork。
3) 连接的中间流程与查找AP的流程类似,都经过了WifiMonitor对“CONNECTED”消息响应的捕获,最终会广播NETWORK_STATE_CHANGED_ACTION消息,由WifiLayer响应。中间还有一点就是在WifistateTracker中调用configureInterface,通过对DHCP服务器的申请进行IP地址分配。