Android wifi-framework WifiMonitor和WifiNative学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/myvest/article/details/75576828

WifiStateMachine作为wifi-framework层最核心的类,其他很多wifi的类都是为其服务的,接下来记录下对WifiNative和WifiMonitor这两个类的学习(阅读《深入理解Android:WiFi模块 NFC和GPS卷 - 邓凡平》和android4.2代码的一些笔记)。
两者都是WifiStateMachine在构造函数中创建的,是WifiStateMachine中重要的成员。

1、WifiNative

WifiNative是一个接口类,主要是提供一些native方法用于wifi-framework层和WPAS通信。WifiNative的主要实现都在wifi.c函数,WifiNative不过是将其封装,供framework层调用。

底层的相关代码在:
framework/base/jni/android_net_wifi_WifiNative.cpp和hardware/libhardware_legacy/wifi.cpp

(1)loadDriver:该方法是用于加载wifi驱动,主要实现是调用insmod函数进行wifi驱动的加载,然后根据加载是否成功来设置”wlan.driver.status”属性,值为”ok”/”failed”/”timeout”。
(2)startSupplicant:用于启动WPAS,后续我们将会看到它在WifiStateMachine是如何被调用的。WPAS的启动和dhcpcd的启动类似,都是使用init.svc.xxx属性来启动的,根据不同的平台配置,使用的Supplicant可能不同。
总结下就几个重要的步骤:
首先确定使用的Supplicant,确定init.svc.xxx属性;
然后判断”/data/misc/wifi/wpa_supplicant.conf”配置文件是否存在,因为在WPAS中,将会根据该文件进行wifi配置。
最后设置init.svc.xxx属性启动WPAS,超时时间根据代码设置,启动完成则设置init.svc.xxx为running,否则为stopped。
(3)connectToSupplicant:该函数将通过wpa Ctrl的接口和WPAS建立起交互关系。
该函数首先创建两个wpa_ctrl对象, ctrl_conn用于向WPAS发送命令并接收对应命令的回复, 而monitor_conn用于接收来自WPAS的unsolicited event。
ps:从Client角度来看,它发送给WPAS的命令所对应的回复属于solicited event( 有请求的事件),而CTRL-EVENT事件(用于通知事件)对应为unsolicited event( 未请求的事件)。
然后monitor_conn调用wpa_ctrl_attach函数以启用unsolicited event接收功能。
最后创建一个socketpair, 用于触发WifiNative关闭和WPAS的连接。
(4)waitForEvent:主要是调用wpa_ctrl_recv函数从monitor_conn对象接收来自WPAS的unsolicited event(CTRL-EVENT事件)。
(5)doCommand类命令:其他一些函数,有很多是调用doCommand类,到底层就是调用的wpa_ctrl_request,使用ctrl_conn向WPAS发送命令并得到回复。

2、WifiMonitor

WifiMonitor最主要的内容是创建了一个MonitorThread,用于接收WPAS的消息。
第一部分,该线程调用了waitForEvent函数,等待WPAS的unsolicited event。

public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
                String eventStr = mWifiNative.waitForEvent();

                // Skip logging the common but mostly uninteresting scan-results event
                if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
                    Log.d(TAG, "Event [" + eventStr + "]");
                }
            ......

第二部分,其调用了dispatchEvent函数,用于向WifiStateMachine分发消息。

public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
             ......
                if (mStateMachine != null) {
                    if (dispatchEvent(eventStr)) {
                        break;
                    }
                } else {
                    if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
                    boolean done = false;
                    Iterator<Map.Entry<String, WifiMonitor>> it =
                            mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<String, WifiMonitor> e = it.next();
                        m = e.getValue();
                        mStateMachine = m.mWifiStateMachine;
                        if (dispatchEvent(eventStr)) {
                            done = true;
                        }
                    }
         ......
        }

让我们看下dispatchEvent函数,首先是处理非”CTRL-EVENT-“的消息:

private boolean dispatchEvent(String eventStr) {

            if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
                if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
                        0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
                } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
                    mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
                } else if (eventStr.startsWith(WPS_FAIL_STR)) {
                    handleWpsFailEvent(eventStr);
                } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
                    mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
                } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
                    mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
                } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
                    handleP2pEvents(eventStr);
                } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
                    handleHostApEvents(eventStr);
                }
                else {
                    if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
                }
                return false;
            ......

接下来是主要部分,对”CTRL-EVENT-“的消息消息的处理。分以下三种:
handleSupplicantStateChange处理WPAS的状态变化,并把变化情况发给WifiStateMachine
handleDriverEvent用于处理来Driver的信息。
handleEvent处理DISCONNECTED / CONNECTED / SCAN_RESULTS 三个消息,并把响应的消息发给WifiStateMachine。

private boolean dispatchEvent(String eventStr) {
    ......
 if (event == STATE_CHANGE) {
               handleSupplicantStateChange(eventData);
            } else if (event == DRIVER_STATE) {
                handleDriverEvent(eventData);
            ......
            } else {
                handleEvent(event, eventData);
            }
            mRecvErrors = 0;
            return false;
        }

猜你喜欢

转载自blog.csdn.net/myvest/article/details/75576828