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
    }
时间: 2024-12-08 18:55:12

Android WIFI 分析(一)的相关文章

Android WIFI 分析(二)

本文介绍Wifi 分析线路二:在Setting中打开WiFi功能.扫描网络以及连接网络的流程. WifiSettings 无线网络设置界面 WifiEnabler 相当于无线网络设置开关 WifiDialog 显示的无线网络配置信息由WifiConfigController 来控制和管理 Scanner 用于处理和无线网络扫描相关的工作 1.Settings 操作 无线网络设置界面UI 初始化过程中,WifiSettings 的onActivityCreated() 方法被调用: public

Android -- Wifi连接流程分析

Android -- Wifi连接流程分析 当我们在Android手机上连接一个AP时,间接调用WifiManager的connect()方法: /** * Connect to a network with the given configuration. The network also * gets added to the supplicant configuration. * * For a new network, this function is used instead of a

Android WIFI模块分析

一:什么是WIFI WIFI是一种无线连接技术,可用于手机.电脑.PDA等终端.WIFI技术产生的目的是改善基于IEEE802.11标准的无线网络产品之间的互通性,也就是说WIFI是基于802.11标准的,但WIFI不等同无线网络. 二:Android平台下的WIFI模块 简单介绍一下,WIFI模块的基本功能: 1. 开关WIFI 除了在WIFI设置界面可以开关WIFI,还有其他的方法可以设置,要查看这些开关状态是否一致.还有就是飞行模式对WIFI开关的影响,由于WIFI开和关都有一个时间过程,

android -------- WIFI 详解

今天简单的来聊一下安卓开发中的Wifi,一些常用的基础,主要分为两部分: 1:WiFi的信息 2:WiFi的搜索和连接 现在app大多都需要从网络上获得数据.所以访问网络是在所难免.但是在访问网络之前,我们应该先做一下网络的状态判断.其实在访问网络之前我们要做一些状态判断,对应一些状态判断来做处理,并不是直接使用Http访问网络即可. 很多人在开发就经常把网络这块直接跳过,直接访问网络,一旦断网,各种体验效果不好,不是说app没法用,只是体验效果差.还有,就是我们可能为用户考虑,因为现在一般连网

Android Wi-Fi Display(Miracast)介绍

Android Wi-Fi Display(Miracast)介绍 2012年11月中旬,Google发布了Android 4.2.虽然它和Android 4.1同属Jelly Bean系列,但却添加了很多新的功能.其中,在显示部分,Android 4.2在Project Butter基础上再接再厉,新增了对Wi-Fi Display功能的支持.由此也导致整个显示架构发生了较大的变化. 本文首先介绍Wi-Fi Display的背景知识,然后再结合代码对Android 4.2中Wi-Fi Disp

Android WiFi开发教程(一)——WiFi热点的创建与关闭

相对于BlueTooth,WiFi是当今使用最广的一种无线网络传输技术, 几乎所有智能手机.平板电脑和笔记本电脑都支持Wi-Fi上网.因此,掌握基本的WiFI开发技术是非常必要的.本教程将围绕一个小Demo初步与大家一同探讨WiFi开发. 先上效果图   Demo功能比较简单,四个按钮.两个文本和一个列表.功能主要有创建WiFi热点,关闭WiFi热点,搜索WiFi,连接WiFi,数据通讯.源码会在教程结尾提供. 本章节主要介绍WiFi热点的创建和关闭 需要用到的权限 <uses-permissi

Android Volley分析(二)——实现

在Android Volley分析(一)--结构中主要分析了Volley的基本组件和框架结构,组件主要是定义的接口,也就是说我们可以实现这些接口来定制自己的Volley版本,比如NetWork.Cache.Request等等.Android Volley在com.android.volley.toolbox下已经做了这些工作,下面就看看这些具体的实现内容 先看一个Volley使用的例子 final TextView mTextView = (TextView) findViewById(R.id

Android WIFI 简单用法

随着Wifi的普及,在开发App的时候对wifi的考虑越来越多了.例如程序的升级在wifi下可以省很多流量,在通信软件中的视频通话.可以实现高画质的传输等等,Android提供了WifiManager类来帮助开发者们管理Wifi.下面就简单来说一下WifiManager的简单用法把. 权限: 为了使用WfiManager 我们需要在Androidmanifest.xml 加入权限: //本例中使用了前两个.具体请按照需要添加权限. <uses-permission android:name=&quo

Android多线程分析之四:MessageQueue的实现

罗朝辉 (http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 在前面两篇文章<Android多线程分析之二:Thread的实现>,<Android多线程分析之三:Handler,Looper的实现>中分别介绍了 Thread 的创建,运行,销毁的过程以及 Thread与 Handler,Looper 之间的关联:Thread 在其 run() 方法中创建和运行消息处理循环 Looper,而 Looper::loop() 方法不断地从 Messag