设为首页 收藏本站
查看: 1238|回复: 0

[经验分享] wifi workflow

[复制链接]

尚未签到

发表于 2015-10-1 11:51:24 | 显示全部楼层 |阅读模式
  我把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(&quot;WifiMonitor&quot;);
}
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的流程类&#20284;,都经过了WifiMonitor对“CONNECTED”消息响应的捕获,最终会广播NETWORK_STATE_CHANGED_ACTION消息,由WifiLayer响应。中间还有一点就是在WifistateTracker中调用configureInterface,通过对DHCP服务器的申请进行IP地址分配。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-121291-1-1.html 上篇帖子: Wifi Analyzer (#Android#手机版)(转) 下篇帖子: Linux USB-Wifi Driver
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表