zoukankan      html  css  js  c++  java
  • 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地址分配。

  • 相关阅读:
    C#获取IP信息
    获取百度地图按条件查找的信息
    react中如何实现一个按钮的动态隐藏和显示(有效和失效)
    es6 关于map和for of的区别有哪些?
    js 高级程序设计 第四章学习笔记
    ant design Table合并单元格合并单元格怎么用?
    React中如何实现模态框每次打开都是初始界面
    前端界面布局相关整理之2017
    待改善的代码整理
    cq三期备注说明
  • 原文地址:https://www.cnblogs.com/chengliu/p/3636435.html
Copyright © 2011-2022 走看看