zoukankan      html  css  js  c++  java
  • 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] = {''};
        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] = {''};
        //判断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] = '';
        }
        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() 方法,故此处略去)。

  • 相关阅读:
    bash shell if 命令参数说明
    Linux test命令
    javascript获取事件触发源
    PHP Manual 学习
    js 控制iframe 刷新
    WP7交互特性浅析及APP设计探究
    FirstDayStart点点
    关于Safari的思考(转载)
    如何使控件背景色支持TransparentKey(at Win2k/WinXP 32bit Color Desktop)
    [Bug] VisualStyleRenderer may cause GDI leak!
  • 原文地址:https://www.cnblogs.com/kaifyou/p/6184058.html
Copyright © 2011-2022 走看看