WifiManager(Wifi服务框架介绍)_jame_11的博客-程序员秘密_wifimanager

  本文简要介绍WIFI服务的主要框架以及运作机制

        WIFI框架主要涉及到以下几个对象:WifiService、WifiManager、WifiServiceImpl、WifiStateMachine等。下面来介绍这四个对象的内在联系。


一、WIFI服务的初始化


        WIFI服务的初始化分为两个部分,WifiService的初始化和WifiManager的初始化,下面分别介绍。


1.1、WifiService的初始化流程


        WifiService的初始化流程是在SystemService中被启动的:
[java]  view plain  copy
  1. @SystemServer.java  
  2. private static final String WIFI_SERVICE_CLASS = "com.android.server.wifi.WifiService";  
  3. private void startOtherServices() {  
  4.     mSystemServiceManager.startService(WIFI_SERVICE_CLASS);  
  5. }  
        在这里通过SystemServiceManager将WIFI的主服务(WifiService)启动,然后来看该Service的启动过程:
[java]  view plain  copy
  1. @WifiService.java  
  2. public final class WifiService extends SystemService {  
  3.     private static final String TAG = "WifiService";  
  4.     final WifiServiceImpl mImpl;  
  5.     public WifiService(Context context) {  
  6.         super(context);  
  7.         //创建WifiServiceImpl对象  
  8.         mImpl = new WifiServiceImpl(context);  
  9.     }  
  10.     @Override  
  11.     public void onStart() {  
  12.         //将WifiServiceImpl注册到ServiceManager  
  13.         publishBinderService(Context.WIFI_SERVICE, mImpl);  
  14.     }  
  15.   
  16.   
  17.     @Override  
  18.     public void onBootPhase(int phase) {  
  19.         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {  
  20.             mImpl.checkAndStartWifi();  
  21.         }  
  22.     }  
  23. }  
        以上是WifiService的全部内容,其实该Service只完成了两个任务:
        1、在初始化时,也就是构造方法中,创建WifiServiceImpl对象。
        2、在onStart时,将WifiServiceImpl对象注册到ServiceManager中。

        这里创建的WifiServiceImpl是整个WIFI服务的管理者,他负责将客户端对WIFI的请求分类,然后派发给不同的处理中心。
        下面先来看WifiServiceImpl的属性:
[java]  view plain  copy
  1. public final class WifiServiceImpl extends IWifiManager.Stub {}  
        这说明该类是一个服务的实现类。
        然后来看该对象的初始化过程,也就是构造方法:
[java]  view plain  copy
  1. @WifiServiceImpl.java  
  2. public WifiServiceImpl(Context context) {  
  3.     mContext = context;  
  4.     mInterfaceName =  SystemProperties.get("wifi.interface""wlan0");  
  5.     mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);  
  6.     //创建wifi状态机  
  7.     mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);  
  8.     mWifiStateMachine.enableRssiPolling(true);  
  9.     //初始化各种管理者  
  10.     mBatteryStats = BatteryStatsService.getService();  
  11.     mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);  
  12.     mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);  
  13.     mSettingsStore = new WifiSettingsStore(mContext);  
  14.     HandlerThread wifiThread = new HandlerThread("WifiService");  
  15.     wifiThread.start();  
  16.     mClientHandler = new ClientHandler(wifiThread.getLooper());  
  17.     mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());  
  18.     mWifiController = new WifiController(mContext, this, wifiThread.getLooper());  
  19.     mBatchedScanSupported = mContext.getResources().getBoolean( R.bool.config_wifi_batched_scan_supported);  
  20. }  
        在这里初始化各种与WIFI管理有关的辅助类,其中包含最重要的一个就是WIFI的状态机WifiStateMachine,他是整个WIFI机制的核心。下面来看该状态机的初始化流程:
[java]  view plain  copy
  1. @WifiStateMachine.java  
  2. public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller){  
  3.     super("WifiStateMachine");  
  4.     mContext = context;  
  5.     mInterfaceName = wlanInterface;  
  6.     //创建NetworkInfo对象  
  7.     mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");  
  8.     mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME));  
  9.     //创建各种辅助类  
  10.     IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);  
  11.     mNwService = INetworkManagementService.Stub.asInterface(b);  
  12.     mP2pSupported = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WIFI_DIRECT);  
  13.     mWifiNative = new WifiNative(mInterfaceName);  
  14.     mWifiConfigStore = new WifiConfigStore(context, mWifiNative);  
  15.     mWifiAutoJoinController = new WifiAutoJoinController(context, this, mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);  
  16.     mWifiMonitor = new WifiMonitor(this, mWifiNative);  
  17.     mWifiInfo = new WifiInfo();  
  18.     ......  
  19.     //初始化状态机  
  20.     addState(mDefaultState);  
  21.     addState(mInitialState, mDefaultState);  
  22.     addState(mSupplicantStartingState, mDefaultState);  
  23.     addState(mSupplicantStartedState, mDefaultState);  
  24.     addState(mDriverStartingState, mSupplicantStartedState);  
  25.     addState(mDriverStartedState, mSupplicantStartedState);  
  26.     addState(mScanModeState, mDriverStartedState);  
  27.     addState(mConnectModeState, mDriverStartedState);  
  28.     addState(mL2ConnectedState, mConnectModeState);  
  29.     addState(mObtainingIpState, mL2ConnectedState);  
  30.     addState(mVerifyingLinkState, mL2ConnectedState);  
  31.     addState(mConnectedState, mL2ConnectedState);  
  32.     addState(mRoamingState, mL2ConnectedState);  
  33.     addState(mDisconnectingState, mConnectModeState);  
  34.     addState(mDisconnectedState, mConnectModeState);  
  35.     addState(mWpsRunningState, mConnectModeState);  
  36.     addState(mWaitForP2pDisableState, mSupplicantStartedState);  
  37.     addState(mDriverStoppingState, mSupplicantStartedState);  
  38.     addState(mDriverStoppedState, mSupplicantStartedState);  
  39.     addState(mSupplicantStoppingState, mDefaultState);  
  40.     addState(mSoftApStartingState, mDefaultState);  
  41.     addState(mSoftApStartedState, mDefaultState);  
  42.     addState(mTetheringState, mSoftApStartedState);  
  43.     addState(mTetheredState, mSoftApStartedState);  
  44.     addState(mUntetheringState, mSoftApStartedState);  
  45.     //设置状态机初始模式  
  46.     setInitialState(mInitialState);  
  47.     //启动状态机  
  48.     start();  
  49.     ......  
  50. }  
        我们看到,在WifiStateMachine的初始化过程中创建了大量的辅助类,其中就包括NetworkInfo,他的作用就是标记当前网络的各项属性,比如当前网络的类型、是否可用、是否处于漫游等,然后还创建了许多WIFI的状态机,标识当前WIFI所处的状态,最后将状态机初始状态设置为mInitialState,并将状态机start。
        以上就是WifiService的全部初始化过程,其主要过程分为以下四个部分:
        1、在SystemServer中启动WifiService;
        2、在WifiService启动过程中创建并初始化WifiServiceImpl;
        3、在WifiServiceImpl初始化过程中创建并初始化WifiStateMachine对象;

        4、在WifiStateMachine初始化过程中创建各种状态机并启动他们;


1.2、WifiManager的初始化流程


        WIFI框架还有另外一个初始化流程实在ContextImpl中进行的。
        当系统初始化时, 会在Context对象的实现类ContextImpl中注册一些常用的服务,这样就可以在应用内部通过Context对象的getSystemService()方法来获取相应的服务 。而WIFI在ContextImpl中注册了WifiManager用于向一般应用提供WIFI的服务:
[java]  view plain  copy
  1. @ContextImpl.java  
  2. registerService(WIFI_SERVICE, new ServiceFetcher() {  
  3.     public Object createService(ContextImpl ctx) {  
  4.         IBinder b = ServiceManager.getService(WIFI_SERVICE);  
  5.         IWifiManager service = IWifiManager.Stub.asInterface(b);  
  6.         return new WifiManager(ctx.getOuterContext(), service);  
  7.     }});  
        从这里可以知道两个信息:
        1、应用可以通过Context对象的getSystemService(Context.WIFI_SERVICE)的方法获取到一个WifiManager的对象用于控制WIFI;
        2、WifiManager的创建需要使用ServiceManager的WIFI_SERVICE服务,而这个WIFI_SERVICE就是在WifiService中注册的WifiServiceImpl对象;

        下面来看WifiManager的创建过程:
[java]  view plain  copy
  1. @WifiManager.java  
  2. public WifiManager(Context context, IWifiManager service) {  
  3.     mContext = context;  
  4.     //这里的mService就是创建WifiManager时传递进来的WifiServiceImpl对象  
  5.     mService = service;  
  6.     init();  
  7. }  
  8. private void init() {  
  9.     synchronized (sThreadRefLock) {  
  10.         if (++sThreadRefCount == 1) {  
  11.             //获取WifiServiceImpl中的Messenger对象  
  12.             Messenger messenger = getWifiServiceMessenger();  
  13.             if (messenger == null) {  
  14.                 sAsyncChannel = null;  
  15.                 return;  
  16.             }  
  17.             //创建AsyncChannel通道  
  18.             sHandlerThread = new HandlerThread("WifiManager");  
  19.             sAsyncChannel = new AsyncChannel();  
  20.             sConnected = new CountDownLatch(1);  
  21.             sHandlerThread.start();  
  22.             Handler handler = new ServiceHandler(sHandlerThread.getLooper());  
  23.             //与WifiServiceImpl申请建立单向AsyncChannel  
  24.             sAsyncChannel.connect(mContext, handler, messenger);  
  25.             try {  
  26.                 sConnected.await();  
  27.             } catch (InterruptedException e) {  
  28.                 Log.e(TAG, "interrupted wait at init");  
  29.             }  
  30.         }  
  31.     }  
  32. }  
        从上面WifiManager的初始化过程中我们看到,其初始化的过程中完成了以下两个任务:
        1、用WifiServiceImpl初始化mService对象;
        2、向WifiServiceImpl申请单向的AsyncChannel(想要连接AsyncChannel请点击这里);

        至此,WIFI框架就完成了所有需要初始化的动作,我们用一张流程图来标识该过程:



二、WIFI服务的运作机制


        由于应用操作WIFI是通过WifiManager进行的,那么我们可以从WifiManager开始来查找消息在WIFI内部的传递机制。
        以下是WifiManager提供的几个比较重要的对外接口:
[java]  view plain  copy
  1. //获取所有网络连接  
  2. public List<WifiConfiguration> getConfiguredNetworks() {}  
  3. //添加网络连接  
  4. public int addNetwork(WifiConfiguration config) {}  
  5. //更新网络连接  
  6. public int updateNetwork(WifiConfiguration config) {}  
  7. //是否支持5Ghz  
  8. public boolean is5GHzBandSupported() {}  
  9. //是否支持WIFI热点  
  10. public boolean isPortableHotspotSupported() {}  
  11. //打开关闭WIFI  
  12. public boolean setWifiEnabled(boolean enabled) {}  
  13. //连接某个WIFI  
  14. public void connect(int networkId, ActionListener listener) {}  
  15. //断开当前连接  
  16. public boolean disconnect() {}  
  17. //添加黑名单  
  18. public boolean addToBlacklist(String bssid) {}  
  19. //清除黑名单  
  20. public boolean clearBlacklist() {}  
        我们挑选两个比较典型的方法进行跟踪,分别是:控制WIFI开关的setWifiEnabled()和连接某个WIFI的connect()方法。

        为什么要挑选这两个方法呢?是因为这两个方法分别使用两种方式与WifiService进行通讯


2.1、setWifiEnabled方式


        在该方式中,WifiManager通过直接调用的方式与WifiServiceImpl进行通讯。
[java]  view plain  copy
  1. @WifiManager.java  
  2. public boolean setWifiEnabled(boolean enabled) {  
  3.     try {  
  4.         //直接调用mService的setWifiEnabled方法  
  5.         return mService.setWifiEnabled(enabled);  
  6.     } catch (RemoteException e) {  
  7.         return false;  
  8.     }  
  9. }  


2.2、connect方式


        与setWifiEnabled不同,在该方式中, WifiManager利用与WifiServiceImpl之间的AsyncChannel来交换信息
[java]  view plain  copy
  1. @WifiManager.java  
  2. public void connect(int networkId, ActionListener listener) {  
  3.     if (networkId < 0throw new IllegalArgumentException("Network id cannot be negative");  
  4.     validateChannel();  
  5.     //通过AsyncChannel与WifiServiceImpl传递信息  
  6.     sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));  
  7. }  


2.3、WifiManager小结


        在上面两节中分别介绍了两种WifiManager与WifiServiceImpl通讯的方式,其实不仅是以上两个方法, WifiManager中所有的对外公开的public方法,最终都是通过这两种方式与WifiServiceImpl进行沟通

        我们可以这样理解WifiManager:他是WIFI模块向外部应用透漏出来的接口,其他所有应用都可以通过WifiManager操作WIFI各项功能,但是WifiManager本身并不具备处理请求的能力,而是把所有请求转发给WifiServiceImpl对象,而发送请求的方式就是直接调用或者通过AsyncChannel。


2.4、WifiServiceImpl中对请求的处理


        无论采用何种沟通方式,WifiManager最终都会把应用的请求转交给WifiServiceImpl来处理。那么接下来的流程是怎样的呢?WifiServiceImpl将会如何处理WifiManager转发过来的请求呢?
        我们继续跟踪上面两个方法的调用流程来查看WifiServiceImpl的处理过程。
        先来看setWifiEnabled()方法,该方法是直接由WifiManager调用到WifiServiceImpl中的,其实现如下:
[java]  view plain  copy
  1. @WifiServiceImpl.java  
  2. public synchronized boolean setWifiEnabled(boolean enable) {  
  3.     //权限检查  
  4.     enforceChangePermission();  
  5.   
  6.   
  7.     //权限检查  
  8.     long ident = Binder.clearCallingIdentity();  
  9.     try {  
  10.         if (! mSettingsStore.handleWifiToggled(enable)) {  
  11.             return true;  
  12.         }  
  13.     } finally {  
  14.         Binder.restoreCallingIdentity(ident);  
  15.     }  
  16.     //向WifiController发送请求  
  17.     mWifiController.sendMessage(CMD_WIFI_TOGGLED);  
  18.     return true;  
  19. }  
        在这里我们看到,WifiServiceImpl将请求转交给WifiController来处理。
        下面来看WifiManager中connect()方法的处理,当初WifiManager收到该请求后,通过AsyncChannel的方式向WifiServiceImpl发送CONNECT_NETWORK的请求,那么WifiServiceImpl的接下来就需要在自己的Messenger中处理,而这个Messenger是从getWifiServiceMessenger()中传递给WifiManager的,我们来看是哪个Messenger来处理该请求:
[java]  view plain  copy
  1. @WifiServiceImpl.java  
  2. public Messenger getWifiServiceMessenger() {  
  3.     //权限检查  
  4.     enforceAccessPermission();  
  5.     enforceChangePermission();  
  6.     //这里的Messenger的Handler是mClientHandler  
  7.     return new Messenger(mClientHandler);  
  8. }  
        从这里看到,WifiManager拿到的Messenger中的Handler其实就是mClientHandler,他是在WifiServiceImpl初始化时被创建的:
[java]  view plain  copy
  1. @WifiServiceImpl.java  
  2. public WifiServiceImpl(Context context) {  
  3.     ......  
  4.     HandlerThread wifiThread = new HandlerThread("WifiService");  
  5.     wifiThread.start();  
  6.     mClientHandler = new ClientHandler(wifiThread.getLooper());  
  7. }  
        也就是说WifiManager通过AsyncChannel发送的消息都会在ClientHandler中接收到:
[java]  view plain  copy
  1. private class ClientHandler extends Handler {  
  2.     ClientHandler(android.os.Looper looper) {  
  3.         super(looper);  
  4.     }  
  5.     @Override  
  6.     public void handleMessage(Message msg) {  
  7.         switch (msg.what) {  
  8.             case WifiManager.CONNECT_NETWORK:  
  9.             case WifiManager.SAVE_NETWORK: {  
  10.                WifiConfiguration config = (WifiConfiguration) msg.obj;  
  11.                int networkId = msg.arg1;  
  12.                if (msg.what == WifiManager.SAVE_NETWORK) {  
  13.                }  
  14.                if (msg.what == WifiManager.CONNECT_NETWORK) {  
  15.                    if (config != null) {  
  16.                        //配置config  
  17.                        if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {  
  18.                            config.creatorUid = Binder.getCallingUid();  
  19.                        } else {  
  20.                            config.lastUpdateUid = Binder.getCallingUid();  
  21.                        }  
  22.                    }  
  23.                }  
  24.                if (config != null && config.isValid()) {  
  25.                    //将请求发送给WifiStateMachine  
  26.                    mWifiStateMachine.sendMessage(Message.obtain(msg));  
  27.                } else if (config == null && networkId != WifiConfiguration.INVALID_NETWORK_ID) {  
  28.                    mWifiStateMachine.sendMessage(Message.obtain(msg));  
  29.                } else {  
  30.                    if (msg.what == WifiManager.CONNECT_NETWORK) {  
  31.                        replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED, WifiManager.INVALID_ARGS);  
  32.                    } else {  
  33.                        replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED, WifiManager.INVALID_ARGS);  
  34.                    }  
  35.                }  
  36.                break;  
  37.            }  
  38.         }  
  39.     }  
  40. }  
        从上面这个处理来看,WifiServiceImpl将请求转交给WifiStateMachine来处理。
         其实WifiServiceImpl对请求的处理与WifiManager类似,他本身并不具备处理事物的能力,只是将请求分类后交由不同的处理者去处理
        以上就是整个WIFI框架的初始化以及内部消息处理机制,下面用一张图来标识WIFI内部的消息流:
        
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34500646/article/details/78874619

智能推荐

QT GUI开发(一):保姆级VS2015配置QT开发环境_mozun2020的博客-程序员秘密_vs2015配置qt环境

QT GUI开发(一):保姆级VS2015配置QT开发环境前言一. QT环境搭建1.1 QT安装1.2 VS中安装工具库二. QT简单工程示例三. 小结前言做软件开发,特别是用户图形界面交互方向,QT的应用越来越广泛了,因其可移植性,以及强大的配置库,大有替代VS的MFC的趋势,笔者2011年上大学的时候,一般开发GUI界面工程都还是基于MFC的框架,到了2015年开始研究生学习的时候,考虑到移植到嵌入式平台的应用需求,已经开始应用QT作为自己的毕设GUI界面开发平台了。正好现在自己的工作也主要与Q

intellij idea 插件 ideaVim 用法_weixin_33883178的博客-程序员秘密

intellij idea 插件 ideaVim - Genji_ - 博客园http://www.cnblogs.com/nova-/p/3535636.html IdeaVim插件使用技巧 - - ITeye技术网站http://kidneyball.iteye.com/blog/1828427 Ctrl+Alt+V  --打开或关闭Idea Vim 当打开idea vim后,当前编...

【操作系统】CPU寄存器详解_公子无缘的博客-程序员秘密_cpu 寄存器

寄存器是 CPU 内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行需要的信息。本文将归纳下面几中寄存器:目录一 通用寄存器二 标志寄存器三指令寄存器四 段寄存器五 控制寄存器六 调试寄存器七 描述符寄存器八 任务寄存器九 MSR寄存器一 通用寄存器 最常用的,也是最基础的有8个通用寄存器(注意一般看到的EAX、ECX也是指的这类寄存器再32位CPU上的拓展,另...

android studio : Could not find org.jetbrains.kotlin:kotlin-stdlib-jre7:1.5.31_Mars-xq的博客-程序员秘密

插件版本配置:仓库配置:ext.kotlin_version = '1.5.31'repositories { maven{ url 'https://maven.aliyun.com/repository/google'} maven{ url 'https://maven.aliyun.com/repository/gradle-plugin'} maven{ url 'https://maven.aliyun.com/repository/public'} ma

[USACO09OCT]热浪Heat Wave 洛谷 1339 最短路_A_loud_name的博客-程序员秘密

题目大意单源最短路···········分析写dij就好了, 但是 我写了dij+堆优化版本的。学习了如何使用c++的优先队列。ps:家里的键盘很恶心啊:f5、f7、f11太小了,按不到。 ps:c++的模板正在补全中。code//dij+堆优化版本#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#i

随便推点

VS2019打开项目,出现“无法找到 .NET Core SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配“的错误_搬运工甲的博客-程序员秘密

今天从GitHub上拉下来一个工程,正想要学习的时候,打开工程结果出现了 “无法找到 .NET Core SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配” 的报错,在经过一系列百度之后,得到最简单解决方案:使用cmd命令 dotnet --info 查看自己使用的SDK版本,然后直接找到项目中的 global.json 文件,右键打开,直接修改版...

Realm数据库使用教程(五):删除数据_晓果博客的博客-程序员秘密_realm删除

Realm数据库使用教程(四):更新数据删除数据同步删除(一):先查找到数据:deleteFromRealm(int index)删除指定数据final RealmResults<Student> students = mRealm.where(Student.class).findAll(); mRealm.executeTransaction(new Real

C#字典Dictionary在unity中使用案例_苍狼王unity学院的博客-程序员秘密

C#字典在unity中使用案例1、前言:讲起C#Dictionary,许多人闻之色变,不了解,不清楚,即使知道,了解,也不一定会用,鉴于此,本人特地总结了一个使用字典的案例。2、什么是字典。必须包含名空间System.Collection.GenericDictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值)键必须是唯一的,而值不需要唯一的键和值都可以是任何类型(...

vite项目在jenkins自动打包报错:failed to load config from ../vite.config.js You installed esbuild on_优秀前端人的博客-程序员秘密

vite项目在jenkins自动打包报错找不到esbuild-linux-64在window环境开发用的找不到esbuild-windows-64,在linux环境构建需要使用esbuild-linux-64,找不到esbuild-linux-64就会报错实际报错:error during build:11:21:11 Error: 11:21:11 You installed esbuild on another platform than the one you're currently us

Flink1.11中的CDC Connectors操作实践_jmx_bigdata的博客-程序员秘密_lcfchan的博客-程序员秘密

Flink1.11中的CDC Connectors操作实践_jmx_bigdata的博客-程序员秘密

vscode代码索引_VSCode 配置文件的变量索引_weixin_39646725的博客-程序员秘密

VS Code 的配置文件可以使用一些预设好的变量,更加方便的配置task和debugging。本文将简述一部分自带的变量,这些变量的基本解析格式 ${变量名}。预设变量${workspaceFolder} - VS Code 中打开的文件夹目录 (通常是项目的位置)${workspaceFolderBasename} - 没有任何斜杠 (/)的 VS Code 中打开的文件夹目录${file} ...