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地址分配。

posted on 2011-05-19 20:45  小尾巴猴子  阅读(236)  评论(0编辑  收藏  举报

导航