博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
wifi流程详细分析
阅读量:4155 次
发布时间:2019-05-25

本文共 16015 字,大约阅读时间需要 53 分钟。

一.启动wifi服务
1.在 SystemServer 启动的时候,会生成一个 ConnectivityService 的实例
路径为:\frameworks\base\services\java\com\android\server\SystemServer.java
try {
             Slog.i(TAG, "Connectivity Service");
             connectivity = ConnectivityService.getInstance(context);
             ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
            } catch (Throwable e) {
                Slog.e(TAG, "Failure starting Connectivity Service", e);
            }
2.ConnectivityService 类中private ConnectivityService(Context context) 构造函数创建
    WifiService和WifiStateTracker对象
\frameworks\base\services\java\com\android\server\ConnectivityService.java
Java代码
 
  1.   
  2. for (int netType : mPriorityList) {   
  3.   
  4.             switch (mNetAttributes[netType].mRadio) {   
  5.   
  6.             case ConnectivityManager.TYPE_WIFI:   
  7.   
  8.                 if (DBG) Slog.v(TAG, "Starting Wifi Service.");   
  9.   
  10.                 WifiStateTracker wst = new WifiStateTracker(context, mHandler);   
  11.   
  12.                 WifiService wifiService = new WifiService(context, wst);   
  13.   
  14.                 ServiceManager.addService(Context.WIFI_SERVICE, wifiService);   
  15.   
  16.                 wifiService.startWifi();   
  17.   
  18.                 mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;   
  19.   
  20.                 wst.startMonitoring();   
  21.   
  22.                 break;   
  23.   
  24. }   
  25.   
  26. }  
for (int netType : mPriorityList) {            switch (mNetAttributes[netType].mRadio) {            case ConnectivityManager.TYPE_WIFI:                if (DBG) Slog.v(TAG, "Starting Wifi Service.");                WifiStateTracker wst = new WifiStateTracker(context, mHandler);                WifiService wifiService = new WifiService(context, wst);                ServiceManager.addService(Context.WIFI_SERVICE, wifiService);                wifiService.startWifi();                mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;                wst.startMonitoring();                break;}}
3.创建WifiStateTracker和WifiService对象用来启动wifi管理服务WifiStateTracker 会创建  
    WifiMonitor 用来接收来自底层的事件,WifiService 和 WifiMonitor 是整个模块的核心。
4.WifiService 负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor 监视线程和把命令下发
               给 wpa_supplicant
     5. WifiMonitor
               开始运行线程,会请求连接wpa_supplicant,通过调用WifiStateTracker函数connectToSupplicant然后通过wifi.c的wifi_connect_to_supplicant,接着向wpa_ctrl的wpa_ctrl_open。然后通过CreateFile函数向wpa_supplicant读取数据。连接成功后会发送EVENT_SUPPLICANT_CONNECTION消息启动获取DHCP地址线程阻塞调用(当连接上AP的时候,该线程会被执行起来获取IP地址),并记录自己的MAC地址(因为MAC地址不会改变
所以请求一次即可) 接着开启一个死循环处理wpa_supplicant发送的事件。
当用户点击Wi-Fi按钮 的时候WifiEnabler中的onPreferenceChange函数会被调用,再由该函数调用WifiManager的setWifiEnabled函数,它先引用AIDL经由IWifiManager通过Binder机制调用WifiService的 setWifiEnabled设置Wifi开启状态。同时WifiService会发送MESSAGE_ENABLE_WIFI消息,由WifiService的
setWifiEnabledBlocking函数响应该消息,负责Wifi可用的需要工作。首先他会加载驱动
loadDriver(),然后开启wpa_supplicant( 配 置 文 件 硬 编 码 为
"/data/misc/wifi/wpa_supplicant.conf") 再注册广播消息,而后通过 WifiStateTracker 来启动 WifiMonitor 中的监视线程。以上工作使能成功后,会调用setWifiEnabledState最后广播WIFI_STATE_CHANGED_ACTION 这个Intent,至此Wifi能动开启。
接下来是扫描AP。
WifiSettings和WifiEnabler 创 建 的 时 候 就 会 向 Android 注 册 接 收
WIFI_STATE_CHANGED_ACTION,因此他们都会收到WIFI_STATE_CHANGED_ACTION 这个Intent,WifiEnabler负责使得图标加亮,WifiSettings负责使得开启扫描AP。经由
WifiService 的 startScan,再通过JNI由android_net_wifi_scanCommand函数向wpa_supplicant发送扫描命令.当 wpa_supplicant 处理完 SCAN 命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event 函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行来处理接扫描结果事件。此线程通过WifiStateTracker 广播 SCAN_RESULTS_AVAILABLE_ACTION这个Intent。而WifiSettings注册了接收此Intent,最终由其相应函数updateAccessPoints将AP列表,以GUI的形式列出来。
当用户选择一个AP时会弹出一个AP参数配置对话框,此对话框会显示当前选择的AP信号强度,若此AP设置了密码则需要用户输入密码才能登录。WifiSettings中的 onPreferenceTreeClick会被调用
Java代码
 
  1. public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {   
  2.   
  3.          //点击AP响应函数  
  4.   
  5.         if (preference instanceof AccessPoint) {   
  6.   
  7.             mSelected = (AccessPoint) preference;   
  8.   
  9.             showDialog(mSelected, false);   
  10.   
  11.         } else if (preference == mAddNetwork) {   
  12.   
  13.             mSelected = null;   
  14.   
  15.             showDialog(nulltrue);   
  16.   
  17.         } else if (preference == mNotifyOpenNetworks) {   
  18.   
  19.             Secure.putInt(getContentResolver(),   
  20.   
  21.                     Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,   
  22.   
  23.                     mNotifyOpenNetworks.isChecked() ? 1 : 0);   
  24.   
  25.         } else {   
  26.   
  27.             return super.onPreferenceTreeClick(screen, preference);   
  28.   
  29.         }   
  30.   
  31.         return true;   
  32.   
  33.     }  
public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {         //点击AP响应函数        if (preference instanceof AccessPoint) {            mSelected = (AccessPoint) preference;            showDialog(mSelected, false);        } else if (preference == mAddNetwork) {            mSelected = null;            showDialog(null, true);        } else if (preference == mNotifyOpenNetworks) {            Secure.putInt(getContentResolver(),                    Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,                    mNotifyOpenNetworks.isChecked() ? 1 : 0);        } else {            return super.onPreferenceTreeClick(screen, preference);        }        return true;    }
用户配置好之后点击连接按钮,onClick函数会被调用。
Java代码
 
  1. public void onClick(DialogInterface dialogInterface, int button) {   
  2.   
  3.           //点击连接按钮的响应函数  
  4.   
  5.         if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {   
  6.   
  7.             forget(mSelected.networkId);   
  8.   
  9.         } else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) {   
  10.   
  11.             WifiConfiguration config = mDialog.getConfig();   
  12.   
  13.     
  14.   
  15.             if (config == null) {   
  16.   
  17.                 if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {   
  18.                     connect(mSelected.networkId);   
  19.                 }   
  20.             } else if (config.networkId != -1) {   
  21.                 if (mSelected != null) {   
  22.                     mWifiManager.updateNetwork(config);   
  23.                     saveNetworks();   
  24.                 }   
  25.             } else {   
  26.                 int networkId = mWifiManager.addNetwork(config);   
  27.                 if (networkId != -1) {   
  28.                     mWifiManager.enableNetwork(networkId, false);   
  29.                     config.networkId = networkId;   
  30.                     if (mDialog.edit || requireKeyStore(config)) {   
  31.                         saveNetworks();   
  32.                     } else {   
  33.                         connect(networkId);   
  34.                     }   
  35.                 }   
  36.             }   
  37.         }  
public void onClick(DialogInterface dialogInterface, int button) {          //点击连接按钮的响应函数        if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {            forget(mSelected.networkId);        } else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) {            WifiConfiguration config = mDialog.getConfig();             if (config == null) {                if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {                    connect(mSelected.networkId);                }            } else if (config.networkId != -1) {                if (mSelected != null) {                    mWifiManager.updateNetwork(config);                    saveNetworks();                }            } else {                int networkId = mWifiManager.addNetwork(config);                if (networkId != -1) {                    mWifiManager.enableNetwork(networkId, false);                    config.networkId = networkId;                    if (mDialog.edit || requireKeyStore(config)) {                        saveNetworks();                    } else {                        connect(networkId);                    }                }            }        }
连接请求部分
一.Settings的connect函数响应连接,更新网络保存配置,更新设置当前选择的优先级最高,并
    保存。然后通过enableNetwork使得其他网络不可用来进行连接。最后调用WifiManager的
      reconnect函数连接当前选择的网络。
二.WifiManager的reconnect函数通过AIDL的Binder机制,调用WifiService的reconnect函数
三.然后会调用 WifiStateTracker的reconnectCommand函数,通过JNI(android_net_wifi_Wifi)的            
      android_net_wifi_reconnectCommand 函数向WPA_WPASUPPLICANT发送 RECONNECT命令。
四. android_net_wifi_Wifi通过 doCommand(命令名,响应缓冲,响应缓存大小)调用wifi.c中的
      wifi_command函数来发送命令。
五.最后通过 wpa_ctrl的wpa_ctrl_request函数向控制通道发送连接命令。
返回请求部分
六.当连接上之后WPA_SUPPLICANT会向控制通道发送连接成功命令。wifi.c的
      wifi_wait_for_event函数阻塞调用并返回这个命令的字符串(CONNECTED).
七.而后WifiMonitor会被执行来处理这个事件,WifiMonitor 再调用 WifiStateTracker的
     notifyStateChange,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动
    DHCP 去获取 IP 地址,然后广播NETWORK_STATE_CHANGED_ACTION消息,最后由
    WifiSettings类来响应,改变状态和界面信息。
关键函数功能介绍
一.connect函数功能
  1.updateNetwork:updateNetwork(config)会将当前选择连接的AP配置信息
   信息传递进去,配置信息有(网络ID等)。如果网络ID为-1则重新添加网络配置,然后向
   wpa_supplicant 发送SET_NETWORK命令(即通过这个网络ID设置其他一些相关信息,设置
   SSID,密码等)如果网络配置不为-1则直接执行后面步骤即发送SET_NETWORK命令。
  2.saveNetwork:告诉supplicant保存当前网络配置并更新列表。SaveNetwork会调用WifiService的
     saveConfiguration向wpa_supplicant发送SAVE_CONFIG命令保存当前网络配置信息,
    如果返回false,则向wpa_supplicant重新发送RECONFIGURE命令获取配置信息,如果获取信
    息成功后,会Intent一个  NETWORK_IDS_CHANGED_ACTION事件WifiSettings会注册接受
    这个 时间并更新列表。
  3.enableNetwork函数,向系统获取接口名并使得该接口有效。由于之前传递的disableOthers
    为true则向wpa_supplicant发送SELECT_NETWORK(如果传递的为false则发送               
     ENABLE_NETWORK命令),
  4.reconnect函数:连接AP
二.reconnect函数功能:connect函数会调用WifiManager的reconnect然后通过Binder机制调用
   WifiService的reconnect,再由WifiStateTracke调用WifiNative向wpa_supplicant发送
   RECONNECT命令去连接网络,当连接上wpa_supplicant之后会向控制通道发送连接成功的命 
   令,
   wifi_wait_for_event函数阻塞等待该事件的发生,并返回这个命令的字符串(CONNECTED)
 
三.android_net_wifi_Wifi函数的doCommand函数会调用wifi.c的wifi_command函数将上层的命
   令向wpa_supplicant发送。
 
四.wifi_wait_for_event函数以阻塞的方式,等待控制通道传递的事件。当有事件传递过来的时候
   该函数会通过wpa_ctrl的wpa_ctrl_recv函数读取该事件,并以字符串形式返回该事件名。
Java代码
 
  1. int wifi_wait_for_event(char *buf, size_t buflen)   
  2.   
  3. {   
  4.   
  5.                        .......   
  6.   
  7.     result = wpa_ctrl_recv(monitor_conn, buf, &nread);   
  8.   
  9.     if (result < 0) {   
  10.   
  11.         LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));   
  12.   
  13.         strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);   
  14.   
  15.         buf[buflen-1] = '\0';   
  16.   
  17.         return strlen(buf);   
  18.   
  19.     }   
  20.   
  21.     buf[nread] = '\0';   
  22.   
  23.     /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */  
  24.   
  25.     /* Check for EOF on the socket */  
  26.   
  27.     if (result == 0 && nread == 0) {   
  28.   
  29.         /* Fabricate an event to pass up */  
  30.   
  31.         LOGD("Received EOF on supplicant socket\n");   
  32.   
  33.         strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);   
  34.   
  35.         buf[buflen-1] = '\0';   
  36.   
  37.         return strlen(buf);   
  38.   
  39.     }   
  40.   
  41.     /* 
  42.  
  43.      * Events strings are in the format 
  44.  
  45.      * 
  46.  
  47.      *     <N>CTRL-EVENT-XXX 
  48.  
  49.      * 
  50.  
  51.      * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, 
  52.  
  53.      * etc.) and XXX is the event name. The level information is not useful 
  54.  
  55.      * to us, so strip it off. 
  56.  
  57.      */  
  58.   
  59.     if (buf[0] == '<') {   
  60.   
  61.         char *match = strchr(buf, '>');   
  62.   
  63.         if (match != NULL) {   
  64.   
  65.             nread -= (match+1-buf);   
  66.   
  67.             memmove(buf, match+1, nread+1);   
  68.   
  69.         }   
  70.   
  71.     }   
  72.     return nread;   
  73. }  
int wifi_wait_for_event(char *buf, size_t buflen){                       .......    result = wpa_ctrl_recv(monitor_conn, buf, &nread);    if (result < 0) {        LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));        strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);        buf[buflen-1] = '\0';        return strlen(buf);    }    buf[nread] = '\0';    /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */    /* Check for EOF on the socket */    if (result == 0 && nread == 0) {        /* Fabricate an event to pass up */        LOGD("Received EOF on supplicant socket\n");        strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);        buf[buflen-1] = '\0';        return strlen(buf);    }    /*     * Events strings are in the format     *     *     
CTRL-EVENT-XXX * * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, * etc.) and XXX is the event name. The level information is not useful * to us, so strip it off. */ if (buf[0] == '<') { char *match = strchr(buf, '>'); if (match != NULL) { nread -= (match+1-buf); memmove(buf, match+1, nread+1); } } return nread;}
五.wpa_ctrl_request,通过socket方式向wpa_supplicant发送命令,以select模式阻塞在
   wpa_supplicant发送和接收。
Java代码
 
  1. 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))   
  2.   
  3. {   
  4.   
  5.          .......   
  6.   
  7.                    res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);   
  8.   
  9.                    if (FD_ISSET(ctrl->s, &rfds)) {   
  10.   
  11.                             res = recv(ctrl->s, reply, *reply_len, 0);   
  12.   
  13.                             if (res < 0)   
  14.   
  15.                                      return res;   
  16.   
  17.                             if (res > 0 && reply[0] == '<') {   
  18.   
  19.                                      /* This is an unsolicited message from 
  20.  
  21.                                       * wpa_supplicant, not the reply to the 
  22.  
  23.                                       * request. Use msg_cb to report this to the 
  24.  
  25.                                       * caller. */  
  26.   
  27.                                      if (msg_cb) {   
  28.   
  29.                                                /* Make sure the message is nul 
  30.  
  31.                                                 * terminated. */  
  32.   
  33.                                                if ((size_t) res == *reply_len)   
  34.   
  35.                                                         res = (*reply_len) - 1;   
  36.   
  37.                                                reply[res] = '\0';   
  38.   
  39.                                                msg_cb(reply, res);   
  40.   
  41.                                      }   
  42.   
  43.                                      continue;   
  44.   
  45.                             }   
  46.   
  47.                             *reply_len = res;   
  48.   
  49.                             break;   
  50.                    } else {   
  51.                             return -2;   
  52.                    }   
  53.          }   
  54.          return 0;   
  55. }  
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)){         .......                   res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);                   if (FD_ISSET(ctrl->s, &rfds)) {                            res = recv(ctrl->s, reply, *reply_len, 0);                            if (res < 0)                                     return res;                            if (res > 0 && reply[0] == '<') {                                     /* This is an unsolicited message from                                      * wpa_supplicant, not the reply to the                                      * request. Use msg_cb to report this to the                                      * caller. */                                     if (msg_cb) {                                               /* Make sure the message is nul                                                * terminated. */                                               if ((size_t) res == *reply_len)                                                        res = (*reply_len) - 1;                                               reply[res] = '\0';                                               msg_cb(reply, res);                                     }                                     continue;                            }                            *reply_len = res;                            break;                   } else {                            return -2;                   }         }         return 0;}
六.WifiMonitor 维护一个监视线程分发处理底层返回上来的事件
Java代码
 
  1. void handleEvent(int event, String remainder) {   
  2.   
  3.             switch (event) {   
  4.   
  5.                 case DISCONNECTED:   
  6.   
  7.                     handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);   
  8.   
  9.                     break;   
  10.   
  11.                 case CONNECTED:   
  12.   
  13.                     handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);   
  14.   
  15.                     break;   
  16.   
  17.                 case SCAN_RESULTS:   
  18.   
  19.                     mWifiStateTracker.notifyScanResultsAvailable();   
  20.   
  21.                     break;   
  22.   
  23.                 case UNKNOWN:   
  24.   
  25.                     break;   
  26.   
  27.             }   
  28.   
  29.         }  
void handleEvent(int event, String remainder) {            switch (event) {                case DISCONNECTED:                    handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);                    break;                case CONNECTED:                    handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);                    break;                case SCAN_RESULTS:                    mWifiStateTracker.notifyScanResultsAvailable();                    break;                case UNKNOWN:                    break;            }        }
此时返回的事件是CONNECTED因此 handleNetworkStateChange会被调用,验证一下BSSID,重新获得networkId
,然后调用WifiStateTracke的notifyStateChange通知状态改变了的消息(EVENT_NETWORK_STATE_CHANGED)
接着处理这个消息,会移除可用网络通告,然后通过 configureInterface()的动态获取IP地址。最后
发送一个NETWORK_STATE_CHANGED_ACTION Intent,WifiSetings注册了此Intent因此会响应该它。由updateConnectionState函数响应。
七.updateConnectionState 获取连接信息,更新列表状态,设置为Connected,然后设置当前网络为可用状态
Java代码
 
  1. private void updateConnectionState(DetailedState state) {   
  2.   
  3.         /* sticky broadcasts can call this when wifi is disabled */  
  4.   
  5.         if (!mWifiManager.isWifiEnabled()) {   
  6.   
  7.             mScanner.pause();   
  8.   
  9.             return;   
  10.   
  11.         }   
  12.   
  13.     
  14.   
  15.         if (state == DetailedState.OBTAINING_IPADDR) {   
  16.   
  17.             mScanner.pause();   
  18.   
  19.         } else {   
  20.   
  21.             mScanner.resume();   
  22.   
  23.         }   
  24.   
  25.     
  26.   
  27.         mLastInfo = mWifiManager.getConnectionInfo();   
  28.   
  29.         if (state != null) {   
  30.   
  31.             mLastState = state;   
  32.   
  33.         }   
  34.   
  35.     
  36.   
  37.         for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {   
  38.   
  39.             ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState);   
  40.   
  41.         }   
  42.   
  43.     
  44.   
  45.         if (mResetNetworks && (state == DetailedState.CONNECTED ||   
  46.   
  47.                 state == DetailedState.DISCONNECTED || state == DetailedState.FAILED)) {   
  48.   
  49.             updateAccessPoints();   
  50.   
  51.             enableNetworks();   
  52.   
  53.         }   
  54.   
  55.     }  
private void updateConnectionState(DetailedState state) {        /* sticky broadcasts can call this when wifi is disabled */        if (!mWifiManager.isWifiEnabled()) {            mScanner.pause();            return;        }         if (state == DetailedState.OBTAINING_IPADDR) {            mScanner.pause();        } else {            mScanner.resume();        }         mLastInfo = mWifiManager.getConnectionInfo();        if (state != null) {            mLastState = state;        }         for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {            ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState);        }         if (mResetNetworks && (state == DetailedState.CONNECTED ||                state == DetailedState.DISCONNECTED || state == DetailedState.FAILED)) {            updateAccessPoints();            enableNetworks();        }    }
 
 
 
 

Wifi 各类之间关系

转载地址:http://opwxi.baihongyu.com/

你可能感兴趣的文章
实验5-8 综合练习
查看>>
第2章实验补充C语言中如何计算补码
查看>>
深入入门正则表达式(java) - 命名捕获
查看>>
使用bash解析xml
查看>>
android系统提供的常用命令行工具
查看>>
【Python基础1】变量和字符串定义
查看>>
【Python基础2】python字符串方法及格式设置
查看>>
【Python】random生成随机数
查看>>
【Python基础3】数字类型与常用运算
查看>>
【Python基础4】for循环、while循环与if分支
查看>>
【Python基础6】格式化字符串
查看>>
【Python基础7】字典
查看>>
【Python基础8】函数参数
查看>>
【Python基础9】浅谈深浅拷贝及变量赋值
查看>>
Jenkins定制一个具有筛选功能的列表视图
查看>>
【Python基础10】探索模块
查看>>
【Python】将txt文件转换为html
查看>>
[Linux]Shell脚本实现按照模块信息拆分文件内容
查看>>
idea添加gradle模块报错The project is already registered
查看>>
在C++中如何实现模板函数的外部调用
查看>>