Android WIFI 分析(一)


本文基於《深入理解Android WiFi NFC和GPS 卷》和 Android N 代碼結合分析
 
WifiService 是 Frameworks中負責wifi功能的核心服務,它主要借助wpa_supplicant(簡稱WPAS)來管理和控制Android 平台中的wifi 功能。
將通過兩條線路來分析WifiService 服務:
1、WifiService 的創建及初始化;
2、在Setting中打開WiFi功能、掃描網絡以及連接網絡的流程;
最后介紹WifiWatchdogStateMachine 和 Captive Portal Check 這兩個知識點。
 
WIFIService 的創建及初始化

WifiService 在SystemService 進程中被創建,Wifi 相關對象定義:

/frameworks/base/services/java/com/android/server/SystemServer.java

    private static final String WIFI_SERVICE_CLASS =
            "com.android.server.wifi.WifiService";
    private static final String WIFI_NAN_SERVICE_CLASS =
            "com.android.server.wifi.nan.WifiNanService";
    private static final String WIFI_P2P_SERVICE_CLASS =
            "com.android.server.wifi.p2p.WifiP2pService";

SystemService 類進程啟動方法run() 調用startOtherService() 方法創建WifiService 進程:

                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_NAN)) {
                    mSystemServiceManager.startService(WIFI_NAN_SERVICE_CLASS);//mSystemServiceManager 進程管理對象在run()方法中創建
                } else {
                    Slog.i(TAG, "No Wi-Fi NAN Service (NAN support Not Present)");
                }
                mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
                mSystemServiceManager.startService(
                            "com.android.server.wifi.scanner.WifiScanningService");

                if (!disableRtt) {
                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
                }

對SystemService的研究可參考《深入理解Android:卷II》第3章

WifiService 繼承SystemService,包名com.android.service.wifi,其構造函數初始化一個WifiServiceImpl 對象:

public final class WifiService extends SystemService {

    private static final String TAG = "WifiService";
    final WifiServiceImpl mImpl;

    public WifiService(Context context) {
        super(context);
        mImpl = new WifiServiceImpl(context);
    }
}

在此,先介紹兩個知識點,分別是HSM(Hierarchical State Machine,結構化狀態機)和AsyncChannel。

 

HSM 和AsyncChannel 介紹

HSM(對應的類是StateMachine) 和AsyncChannel 是Android Framework 中兩個重要的類。

HSM 中的狀態層級關系與Java中父子類的派生和繼承關系類似,即在父狀態中實現generic 的功能,而在子狀態中實現一些特定的處理;不過與Java 中類派生不同的是,HSM 中父子狀態對應的是毫無派生關系的兩個類,使用時需要創建兩個對象。

AsyncChannel 用於兩個Handler 之間的通信,具體的通信方式為源Handler 通過sendMessage 向目標Handler 發送消息,而目標Handler 通過replyToMessage 回復源Handler 處理結果;這兩個Handler 可位於同一個進程,也可分屬於兩個不同的進程。

1、HSM 的使用

addState():添加一個狀態。同時還可指定父狀態

transitionTo():將狀態機切換到某個狀態

obtainMessage():HSM內部是圍繞一個Handler來工作的,外界只能調用HSM的obtainMessage()以獲取一個Message

sendMessage():發送消息給HSM。HSM 中的Handler 會處理它

deferMessage():保留某個消息,該消息將留待下一個新狀態中去處理

start():啟動狀態機

quit()、quitNow():停止狀態機

HSM 中狀態和狀態直接的層級關系體現在:

1) SM啟動后,初始狀態的EA將按派生順序執行,即其祖先狀態先執行,子狀態后執行

2) 當State發送切換時,舊State的exit 先執行,新State 的enter 后執行,並且新舊State 派生樹上對應的State 也需要執行exit 或 enter 函數。類似C++ 類構造/析構函數執行順序

3) State 處理Message 時,如子狀態不能處理(返回NOT_HANDLED),則交給父狀態去處理

2、AsyncChannel 的使用

1) 簡單的request/response 模式下,Server 端無須維護Client 的信息,它只要處理來自Client 的請求即可。

Client 調用connectSync(同步連接)或connect(異步連接,連接成功后Client 會收到CMD_CHANNEL_HALF_CONNECTED 消息)即可連接到Server。

2) 與request/response 模式相反,即Server 端維護Client 的信息。

Server 可以向Client 發送自己的狀態或者其他一些有意義的信息。wpa_cli 和wpa_supplicant 就是此模式的應用,wpa_cli 可以發送命令給WPAS 去執行;同時,WPAS 也會將自己的狀態及其他一些信息通知給 wpa_cli。

以異步方式為例介紹第2種應用模式中AsyncChannel 的使用步驟:

1) Client 調用AsyncChannel 的connect() 函數,Client 的Handler 會收到一個名為CMD_CHANNEL_HALF_CONNECTED 消息;

2) Client 在處理CMD_CHANNEL_HALF_CONNECTED 消息時,需通過sendMessage() 函數向Server 端發送一個名為 CMD_CHANNEL_FULL_CONNECTION 的消息;

3) Server 端的Handler 將收到此CMD_CHANNEL_FULL_CONNECTION 消息,成功處理它后,Server 端先調用AsyncChannel 的connected() 函數,然后通過sendMessage() 函數向Client 端發送CMD_CHANNEL_FULLY_CONNECTED 消息;

4) Client 端收到CMD_CHANNEL_FULLY_CONNECTED 消息。至此,Client 和Server 端成功建立連接。

5) Clinet 和Server 端的兩個Handler 可借助sendMessage() 和replyToMessage() 來完成請求消息及回復消息的傳遞。注意,只有針對那些需要回復的情況,Server 端才需調用replyToMessage()。

6) Client 和Server 的任意一端都可以調用disconnect() 函數以結束連接。該函數將導致Client 和Server 端都會收到CMD_CHANNEL_DISCONNECTED 消息。

注此部分流程描述來自AsyncChannel.java 文件中的注釋,但實際第3步,AsyncChannel 一般由客戶端創建,Server無法獲取到。接下來通過代碼展示正確的做法。

 

WifiManager 類的getChannel() 函數會創建一個AsyncChannel 以和WifiService 中的ServiceHandler 建立連接關系,並返回AsyncChannel 對象:

    private synchronized AsyncChannel getChannel() {
        if (mAsyncChannel == null) {
            Messenger messenger = getWifiServiceMessenger(); //是Server 端的Handler 在Client 端的代表
            if (messenger == null) {
                throw new IllegalStateException(
                        "getWifiServiceMessenger() returned null!  This is invalid.");
            }

            mAsyncChannel = new AsyncChannel(); //AsyncChannel 一般在Client 端創建
            mConnected = new CountDownLatch(1);
            //ServiceHandler 是WifiManager 定義的內部類Handler
            Handler handler = new ServiceHandler(mLooper); //Client 端的Handler
            mAsyncChannel.connect(mContext, handler, messenger); //mContext 是Client 端的Context 對象
            try {
                mConnected.await();
            } catch (InterruptedException e) {
                Log.e(TAG, "interrupted wait at init");
            }
        }
        return mAsyncChannel;
    }

getWifiServiceMessager() 函數,獲取WifiService 端的Handler 引用,用於Client 與WifiService 建立AsyncChannel 通信:

    public Messenger getWifiServiceMessenger() {
        try {
            return mService.getWifiServiceMessenger(); //返回的Messenger 對象包含WifiService 的Handler
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

mService 是IWifiManager 類對象,其實質是一個AIDL 接口,WifiServiceImpl 類繼承自IWifiManager.Stub,所以getWifiServiceMessenger() 函數的實現在WifiServiceImpl.java 中:

    /**
     * Get a reference to handler. This is used by a client to establish
     * an AsyncChannel communication with WifiService
     */
    public Messenger getWifiServiceMessenger() {
        enforceAccessPermission(); //權限檢查
        enforceChangePermission();
        return new Messenger(mClientHandler); //通過Messenger 封裝了目標Handler
    }

 

connect() 函數將觸發Client 端Handler(即ServiceHandler) 收到一個CMD_CHANNEL_HALF_CONNECTED 消息,由WifiManager 的ServiceHandler 處理:

        private void dispatchMessageToListeners(Message message) {
            Object listener = removeListener(message.arg2);
            switch (message.what) {
                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                    if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { //半連接成功
                        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); //向Server 端發送CMD_CHANNEL_FULL_CONNECTION
                    } else {
                        Log.e(TAG, "Failed to set up channel connection");
                        // This will cause all further async API calls on the WifiManager
                        // to fail and throw an exception
                        mAsyncChannel = null;
                    }
                    mConnected.countDown();
                    break;
                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: //連接成功
                    // Ignore
                    break;
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: //連接關閉
                    Log.e(TAG, "Channel connection lost");
                    // This will cause all further async API calls on the WifiManager
                    // to fail and throw an exception
                    mAsyncChannel = null;
                    getLooper().quit(); //連接關閉,退出線程
                    break;

 

WifiServiceImpl.java 中定義ClientHandler,處理Client 端發送過來的消息:

    /**
     * Handles client connections 處理Client 連接
     */
    private class ClientHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
//處理因ac.connect調用而收到的CMD_CHANNEL_HALF_CONNECTED消息
//該消息攜帶了一個AsyncChannel 對象,即ac
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); // We track the clients by the Messenger // since it is expected to be always available mTrafficPoller.addClient(msg.replyTo); //WifiTrafficPoller 類
                    } break;
                }
                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
                        if (DBG) Slog.d(TAG, "Send failed, client connection lost");
                    } else {
                        if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
                    }
                    mTrafficPoller.removeClient(msg.replyTo);
                    break;
                }
                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { //Server 端先收到此消息
                    AsyncChannel ac = new AsyncChannel(); //新建一個AsyncChannel對象,調用它的connect()函數
                    ac.connect(mContext, this, msg.replyTo); //msg.replyTo 代表Client 端的Handler,即WifiManager 中ServiceHandler
//connect()函數將觸發CMD_CHANNEL_HALF_CONNECTED消息被發送,而且該消息會攜帶對應的AsyncChannel 對象,即此次的ac
break; }

WifiTrafficPoller 類的addClient() 方法:

    void addClient(Messenger client) {
        Message.obtain(mTrafficHandler, ADD_CLIENT, client).sendToTarget();
    }

ADD_CLIENT 消息由該類的內部類TrafficHandler 處理:

                case ADD_CLIENT:
                    mClients.add((Messenger) msg.obj); //保存上面的AsyncChannel 對象,用於向Client發送消息
break;

 由於Server 端無法得到Client 端的AsyncChannel 對象,所以就新創建了一個AsyncChannel,並connect 到Client 端。

 

WifiService 構造函數分析

在上文看到WifiService 的構造函數主要創建一個WifiServiceImpl 對象,所以重點查看WifiServiceImpl 的構造函數:

    public WifiServiceImpl(Context context) {
        HandlerThread wifiThread = new HandlerThread("WifiService");
        wifiThread.start();
        HandlerThread wifiStateMachineThread = new HandlerThread("WifiStateMachine");
        wifiStateMachineThread.start();

        mWifiStateMachine = new WifiStateMachine(mContext, mFacade,
            wifiStateMachineThread.getLooper(), mUserManager, mWifiInjector,
            new BackupManagerProxy(), mCountryCode); //創建一個WifiStateMachine對象
        mWifiStateMachine.enableRssiPolling(true); //RSSI(信號接收強度)輪詢機制
     //WPAS支持的RSSI信息包括:接收信號強度、連接速度(link speed)、噪聲強度(noise)和頻率 mClientHandler
= new ClientHandler(wifiThread.getLooper()); //用於AsyncChannel,其交互對象來自WifiManager mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); //用於AsyncChannel,其交互對象來自WifiStateMachine }

 接下來重點分析WifiStateMachine 類。

 

WifiStateMachine 構造函數分析之一

WifiStateMachine 類繼承自StateMachine,其構造函數:

    public WifiStateMachine(Context context, FrameworkFacade facade, Looper looper,
                            UserManager userManager, WifiInjector wifiInjector,
                            BackupManagerProxy backupManagerProxy,
                            WifiCountryCode countryCode) {
        super("WifiStateMachine", looper);
        //WifiNative 用於和wpa_supplicant 交互
        mWifiNative = WifiNative.getWlanNativeInterface();
        //創建一個NetworkInfo,實際上代表一個網絡設備的狀態信息
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
        //和BatteryStateService 交互,BSS 注冊的服務名叫“batteryinfo”
        mBatteryStats = IBatteryStats.Stub.asInterface(mFacade.getService(
                BatteryStats.SERVICE_NAME));
        //創建和NetworkManagmentService 交互的Binder 客戶端
        IBinder b = mFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
        mNwService = INetworkManagementService.Stub.asInterface(b);
        //判斷系統是否支持Wifi Display功能(WFD)
        mP2pSupported = mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_WIFI_DIRECT);
       //內部將創建一個線程,並借助WifiNative 去接收處理來自WPAS的信息
        mWifiMonitor = WifiMonitor.getInstance();
        //WifiInfo 用於存儲手機當前連接上的無線網絡信息,包括IP地址、ssid 等內容
        mWifiInfo = new WifiInfo();
        //SupplicantStateTracker 用於跟蹤WPAS 的狀態,它是一個StateMachine
        mSupplicantStateTracker = mFacade.makeSupplicantStateTracker(
                context, mWifiConfigManager, getHandler());
        //LinkProperties 用於描述網絡連接(network link)的一些屬性,如IP地址、DNS地址和路由設置
        mLinkProperties = new LinkProperties();
    }

將重點介紹WifiNative、WifiMonitor 以及SupplicantStateTracker

1) WifiNative 用於和WPAS 通信,其內部定義了較多的native 方法(對應的JNI 模塊是com_android_server_wifi_WifiNative.cpp),本文將介紹最重要的兩個方法:

第一個方法是startSupplicant(),用於啟動WPAS。startSupplicant() 方法:

    private native static boolean startSupplicantNative(boolean p2pSupported);
    public boolean startSupplicant(boolean p2pSupported) {
        synchronized (sLock) {
            return startSupplicantNative(p2pSupported);
        }
    }

其JNI 模塊中的定義:

/frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp

static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jclass, jboolean p2pSupported)
{
    return (::wifi_start_supplicant(p2pSupported) == 0);
}

底層wifi_start_supplicant() native方法的定義:

/hardware/libhardware_legacy/wifi/wifi.c

int wifi_start_supplicant(int p2p_supported)
{
    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
    int count = 200; /* wait at most 20 seconds for completion */
    //和 P2P有關
    if (p2p_supported) {
        strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
        strcpy(supplicant_prop_name, P2P_PROP_NAME);//"init.svc.p2p_supplicant"賦值

        /* Ensure p2p config file is created */
        if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
            ALOGE("Failed to create a p2p config file");
            return -1;
        }

    } else {
        strcpy(supplicant_name, SUPPLICANT_NAME);
        strcpy(supplicant_prop_name, SUPP_PROP_NAME);//"init.svc.wpa_suppplicant"賦值
    }
    
    /* Check whether already running */
    if (property_get(supplicant_prop_name, supp_status, NULL)
            && strcmp(supp_status, "running") == 0) {
        return 0; //如果WPAS已經啟動,則直接返回
    }
    //配置文件對應“/data/misc/wifi/wpa_supplicant.conf”
    /* Before starting the daemon, make sure its config file exists */
    if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
        ALOGE("Wi-Fi will not be enabled");
        return -1;
    }
    //entropy 文件,用於增加隨機數生成的隨機性
    if (ensure_entropy_file_exists() < 0) {
        ALOGE("Wi-Fi entropy file was not created");
    }

    /* Clear out any stale socket files that might be left over. */
    wpa_ctrl_cleanup(); //關閉之前創建的wpa_ctrl 對象

    /*
     * Get a reference to the status property, so we can distinguish
     * the case where it goes stopped => running => stopped (i.e.,
     * it start up, but fails right away) from the case in which
     * it starts in the stopped state and never manages to start
     * running at all.
     */
    pi = __system_property_find(supplicant_prop_name);
    if (pi != NULL) {
        serial = __system_property_serial(pi);
    }
    property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
    //通過設置"ctl_start”屬性來啟動wpa_supplicant 服務,該屬性將觸發init fork 一個子進程用於運行wpa_supplicant。同時,init 還會添加一個新的屬性“init.svc.wpa_supplicant”用於跟蹤wpa_supplicant 的狀態
    property_set("ctl.start", supplicant_name);
    sched_yield();
    //此循環用於查詢supplicant_prop_name 的屬性值,如果其值變為“running”,表示wpa_supplicant 成功運行
    while (count-- > 0) { //最多等待20s
        if (pi == NULL) {
            pi = __system_property_find(supplicant_prop_name);
        }
        if (pi != NULL) {
            /*
             * property serial updated means that init process is scheduled
             * after we sched_yield, further property status checking is based on this */
            if (__system_property_serial(pi) != serial) {
                __system_property_read(pi, NULL, supp_status);
                if (strcmp(supp_status, "running") == 0) {
                    return 0; 
                } else if (strcmp(supp_status, "stopped") == 0) {
                    return -1; //如果WPAS 停止運行,則直接返回 -1
                }
            }
        }
        usleep(100000);
    }
    return -1;
}

 

第二個方法是connectToSupplicant(),它將通過WPAS 控制API 和 WPAS 建立交互關系:

    private native static boolean connectToSupplicantNative();
    public boolean connectToSupplicant() {
        synchronized (sLock) {
            localLog(mInterfacePrefix + "connectToSupplicant");
            return connectToSupplicantNative();
        }
    }

其對應JNI 模塊方法:

static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jclass)
{
    return (::wifi_connect_to_supplicant() == 0);
}

其native 方法:

/* Establishes the control and monitor socket connections on the interface */
int wifi_connect_to_supplicant()
{
    static char path[PATH_MAX];
   //IFACE_DIR="/data/system/wpa_supplicant"
    if (access(IFACE_DIR, F_OK) == 0) {
        snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);//primary_iface 為0表示STA,為1表示P2P
    } else {
        snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
    }
    return wifi_connect_on_socket_path(path);
}

查看wifi_connect_on_socket_path() :

int wifi_connect_on_socket_path(const char *path)
{
    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
    //判斷wpa_supplicant 進程是否已經啟動
    /* Make sure supplicant is running */
    if (!property_get(supplicant_prop_name, supp_status, NULL)
            || strcmp(supp_status, "running") != 0) {
        ALOGE("Supplicant not running, cannot connect");
        return -1;
    }
    //創建第一個wpa_ctrl 對象,用於發送命令
    ctrl_conn = wpa_ctrl_open(path);
    ..........
    //創建第二個wpa_ctrl 對象,用於接收unsolicited event
    monitor_conn = wpa_ctrl_open(path);
    ..........
    //必須調用wpa_ctrl_attach 函數以啟用unsolicited event 接收功能
    if (wpa_ctrl_attach(monitor_conn) != 0) {
        .........
    }
    //創建一個socketpair,用於觸發wifiNative 關閉和WPAS 的連接
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
        wpa_ctrl_close(monitor_conn);
        wpa_ctrl_close(ctrl_conn);
        ctrl_conn = monitor_conn = NULL;
        return -1;
    }

    return 0;
}

由於支持兩個並發設備,所以每個並發設置各有兩個wpa_ctrl 對象。

ctrl_conn[PRIMARY]、monitor_conn[PRIMARY]:用於STA 設備;

ctrl_conn 用於向WPAS 發送命令並接收對應命令的回復,而monitor_conn 用於接收來自WPAS 的unsolicited event。

ctrl_conn[SECONDARY]、monitor_conn[SECONDARY]:用於P2P 設備;

另外,exit_sockets 保存了socketpair 創建的socket 句柄,這些句柄用於WifiService 通知WifiNative 去關閉它和WPAS 的連接。

 

wifi_send_command() 使用ctrl_conn 中的wpa_ctrl 對象向WPAS 發送命令並接收回復:

int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
{
    int ret;
    ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
    if (ret == -2) {
        .........
    } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
        return -1;
    }
    if (strncmp(cmd, "PING", 4) == 0) {
        reply[*reply_len] = '\0';
    }
    return 0;
}

wifi_ctrl_recv() 使用monitor_conn 中的wpa_ctrl 對象接收來自WPAS 的消息:

int wifi_ctrl_recv(char *reply, size_t *reply_len)
{
    int res;
    int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
    struct pollfd rfds[2];

    memset(rfds, 0, 2 * sizeof(struct pollfd));
    rfds[0].fd = ctrlfd;
    rfds[0].events |= POLLIN;
    rfds[1].fd = exit_sockets[1];
    rfds[1].events |= POLLIN;
    do {
        res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
        if (res < 0) {
            ALOGE("Error poll = %d", res);
            return res;
        } else if (res == 0) {
            /* timed out, check if supplicant is active
             * or not ..
             */
            res = wifi_supplicant_connection_active();
            if (res < 0)
                return -2;
        }
    } while (res == 0);

    if (rfds[0].revents & POLLIN) {
        return wpa_ctrl_recv(monitor_conn, reply, reply_len);
    }

    /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
     * or we timed out. In either case, this call has failed ..
     */
    return -2;
}

 

2) WifiMonitor 最重要的內容是其內部的WifiMonitor 線程,該線程專門用於接收來自WPAS 的消息

    private class MonitorThread extends Thread {
        ........
        public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
                if (!mConnected) { //判斷與WPAS 是否連接成功
                    if (DBG) Log.d(TAG, "MonitorThread exit because mConnected is false");
                    break;
                }
                 //waitForEvent() 內部調用WifiNative 的waitForEventNative()
                String eventStr = mWifiNative.waitForEvent();

                // Skip logging the common but mostly uninteresting events
                if (!eventStr.contains(BSS_ADDED_STR) && !eventStr.contains(BSS_REMOVED_STR)) {
                    if (DBG) Log.d(TAG, "Event [" + eventStr + "]");
                    mLocalLog.log("Event [" + eventStr + "]");
                }
                //解析WPAS 消息
                if (dispatchEvent(eventStr)) {
                    if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
                    break;
                }
            }
        }
    }    

dispatchEvent() 方法解析以及處理WPAS 的狀態,重點分析其中的方法:

handleSupplicantStateChange() 用於處理WPAS 的狀態變化,它把這些信息交給WifiStateMachine 去處理;而WifiStateMachine 將根據處理情況是否需要由SupplicantStateTracker 來處理。

handleDirverEvent() 用於處理來自Driver 的信息。

handleEvent() 用於處理其他消息事件,此函數定義如下:

WPAS 的狀態指的是wpa_sm 狀態機中的狀態,包括WPA_DISCONNECTED、WPA_SCANNING等;WifiService 定義了SupplicantState 類來描述WPAS 的狀態,包括DISCONNECTED、SCANNING等。

    private void handleEvent(int event, String remainder, String iface) {
        switch (event) {
            case DISCONNECTED:                handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder, iface);
                break;
            case CONNECTED: //該事件表示WPAS 成功加入一個無線網絡                handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder, iface);
                break;
            case SCAN_RESULTS: //表示WPAS 已經完成掃描,客戶端可以來查詢掃描結果
                sendMessage(iface, SCAN_RESULTS_EVENT); //處理掃描結果消息
                break;
            case UNKNOWN:
            ...........
            default:
                break;
        }
    }

 

3) SupplicantStateTracker 用於跟蹤和處理WPAS 的狀態變化。

在WifiService 中,WPAS 的狀態有SupplicantState 來表示,而管理狀態模塊就是SupplicantStateTracker。

SupplicantStateTracker 繼承StateMachine,還定義了8個狀態對象,其構造方法:

    public SupplicantStateTracker(Context c, WifiConfigManager wcs, Handler t) {
        super(TAG, t.getLooper());

        mContext = c;
        mWifiConfigManager = wcs;
        mBatteryStats = (IBatteryStats)ServiceManager.getService(BatteryStats.SERVICE_NAME);
        addState(mDefaultState);
            addState(mUninitializedState, mDefaultState);
            addState(mInactiveState, mDefaultState);
            addState(mDisconnectState, mDefaultState);
            addState(mScanState, mDefaultState);
            addState(mHandshakeState, mDefaultState);
            addState(mCompletedState, mDefaultState);
            addState(mDormantState, mDefaultState);

        setInitialState(mUninitializedState);//設置初始狀態
        //start the state machine
        start(); //啟動狀態機
    }

SupplicantState 中的AUTHENTICATING、ASSOCIATING、ASSOCIATED、FOUR_WAY_HANDSHAKE 和GROUP_HANDSHAKE 均對應此處的mHandshakeState;

SupplicantState 中的UNINITIALZED 和NVALID 對應此處的mUninitializedState;

 

WifiStateMachine 構造函數分析之二

        // CHECKSTYLE:OFF IndentationCheck
        addState(mDefaultState); //wifi 狀態很多
            addState(mInitialState, mDefaultState);
            .........
            addState(mSupplicantStoppingState, mDefaultState);
            addState(mSoftApState, mDefaultState);
        // CHECKSTYLE:ON IndentationCheck

        setInitialState(mInitialState); //設置初始化狀態

WifiStateMachine 的初始狀態是mInitialState,其類型是InitialState。對HSN的介紹,其enter() 方法將被調用(由於InitialState 的父狀態DefaultState 並未實現enter() 方法,故此處略去)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM