简单分析下wifi相关类,首先了解几个主要概念

AsyncChannel

简单理解:

AsyncChannel,就是借助Messenger 机制,让两个不同的handler之间进行通信。

AsyncChannel类有两个Messenger对象:mSrcMessenger,mDstMessenger。

mSrcMessenger,一般用于封装源端handler对象

mDstMessenger,一般用于封装目的端handler对象

而后,调用AsyncChannel的sendMessage方法时,执行两个操作:

1. msg.replyTo = mSrcMessenger; //重设消息的replyTo值

2. mDstMessenger.send(msg); //该方法就会将消息发送给目的端的handler去处理

由于重设了消息的replyTo值,之后在目的端发出的消息,将返回给源端handler处理。

参考:Android源码阅读笔记:AsyncChannel与层次状态机StateMachine

wifi 相关文件

  1. framework
  2. WifiManager
  3. 管理所有wifi操作,提供API调用,主要用于上层应用调用
  4. WifiService
  5. 处理Wifi操作请求。一般都是在WifiManager中被调用
  6. WifiStateMachine
  7. 处理wifi各个阶段状态所要处理的消息
  8. WifiMonitor
  9. 监听所有来自wpa_supplicant的事件,并传递给WifiStateMachine处理
  10. WifiNative
  11. native方法,发送消息给wpa_supplicant
  12.  
  13. jni
  14. android_net_wifi_Wifi.cpp
  15.  
  16. wpa_supplicant适配器层
  17. wifi.c
  18.  
  19. wpa_supplicant
  20. wpa_supplicant.c

接下来分析wifi启动、扫描、连接ap的流程。

一、 Wifi相关类创建

  1. 1.SystemServer::ServerThread::run---->new WifiService(...);
  2.  
  3. 2.WifiService(...)---->new WifiStateMachine(...);
  4.  
  5. 3.WifiStateMachine(...)
  6.  
  7. ---->new WifiNative(...)
  8.  
  9. ---->new WifiMonitor(...)
  10.  
  11. ---->AsyncChannel::connectSync(...)
  12.  
  13. ps: AsyncChannel::connectSyncWifiStateMachinewifiApConfigStore通过AsyncChannel关联起来。
  14.  
  15. 4. SystemServer::ServerThread::run ServiceManager.addService(...);

over~~

-----------------------------------------------------------------

二、 wifi功能启动

先贴出整体流程时序图

1. 检查系统属性中的wifi状态信息

  1. SystemServer::ServerThread::run
  2. --->WifiService::checkAndStartWifi (该方法只在开机时调用,用来检查wifi是否需要开启)

分析WifiService::checkAndStartWifi方法:

  1. public void checkAndStartWifi() {
  2. mAirplaneModeOn.set(isAirplaneModeOn());
  3. mPersistWifiState.set(getPersistedWifiState());
  4. /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
  5. boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
  6. Slog.i(TAG, "WifiService starting up with Wi-Fi " +
  7. (wifiEnabled ? "enabled" : "disabled"));
  8.  
  9. // If we are already disabled (could be due to airplane mode), avoid changing persist
  10. // state here
  11. if (wifiEnabled) setWifiEnabled(wifiEnabled);
  12.  
  13. mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
  14. makeWifiWatchdogStateMachine(mContext); //以后分析
  15.  
  16. }

(1)isAirplaneModeOn()/getPersistedWifiState():都是获取系统属性进行判断。

(2)shouldWifiBeEnabled():判断mAirplaneModeOn/mPersistWifiState中的值,其实就是上述两个方法获得的值。

(3)testAndClearWifiSavedState():获取系统属性中保存的wifi状态的值,返回,之后清空状态,置为0。

另注意:以下分析都是基于条件:开机启动时,wifi状态为on。

因此,接着会调用setWifiEnabled(true)方法,下面分析。

到此,检查wifi系统属性状态的操作结束,over~~

2.setWifiEnabled(true)执行流程

2.1

该方法中主要执行以下语句:

  1. if (FeatureQuery.FEATURE_CT_FMC_SUPPORT && WifiManager.fmcV2Support()) {
  2. mWifiStateMachine.fmcV2SetWifiEnabled(enable);
  3. } else {
  4. mWifiStateMachine.setWifiEnabled(enable);
  5. }

分析:

  1. FeatureQuery.FEATURE_CT_FMC_SUPPORT/WifiManager.fmcV2Support()

(1)FeatureQuery.FEATURE_CT_FMC_SUPPORT

这个属性值在build/buildplus/target/FeatureQuery.java里可以找到。

(2)WifiManager::fmcV2Support方法如下:

  1. public static boolean fmcV2Support() {
  2. return (SystemProperties.getInt("ro.config.cwenable", 0) == 1)
  3. && (SystemProperties.getInt("ro.config.fmcv2support", 0) == 1);
  4. }

就是获取两个系统属性,判断是否支持FMC功能,有两种方式可以查看

(a)在out/target/product/msm8625/system/build.prop中可以找到

(b)命令提示符下,adb shell,然后使用命令:getprop XX ,就可以获得属性值。XX表示系统属性名。

总结:这两个条件的作用就是判断是否支持FMC功能(固定网络与移动网络融合)。

2.2

执行mWifiStateMachine.fmcV2SetWifiEnabled方法:

  1. public void fmcV2SetWifiEnabled(boolean enable) {
  2. if (!enable) {
  3. ......
  4. } else {
  5. setWifiEnabled(enable);
  6. }
  7. }

接着调用WifiStateMachine::setWifiEnabled(enable)方法: 发送两个消息。

  1. public void setWifiEnabled(boolean enable) {
  2. mLastEnableUid.set(Binder.getCallingUid());
  3. if (enable) {
  4. /* Argument is the state that is entered prior to load */
  5. sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
  6. sendMessage(CMD_START_SUPPLICANT);
  7. } else {
  8. ......
  9. }
  10. }

接收CMD_LOAD_DRIVER消息的是DriverUnloadedState状态。

2.4 DriverUnloadedState状态处理

  1. public boolean processMessage(Message message) {
  2. if (DBG) log(getName() + message.toString() + "\n");
  3. switch (message.what) {
  4. case CMD_LOAD_DRIVER:
  5. transitionTo(mDriverLoadingState);
  6. break;
  7. ......
  8. }

在这里CMD_LOAD_DRIVER消息被处理,切换到DriverLoadingState状态。

2.5 DriverLoadingState 处理状态

  1. public void enter() {
  2.   ......
  3.   final Message message = new Message();
  4.   message.copyFrom(getCurrentMessage());
  5.   new Thread(new Runnable() {
  6. public void run() {
  7. mWakeLock.acquire();
  8. //enabling state
  9. switch(message.arg1) {
  10. case WIFI_STATE_ENABLING:
  11. setWifiState(WIFI_STATE_ENABLING);
  12. break;
  13. case WIFI_AP_STATE_ENABLING:
  14. setWifiApState(WIFI_AP_STATE_ENABLING);
  15. break;
  16. }
  17.  
  18. if(mWifiNative.loadDriver()) {
  19. if (DBG) log("Driver load successful");
  20. sendMessage(CMD_LOAD_DRIVER_SUCCESS);
  21. }
  22. .....
  23. }

(1)在enter方法中通过message.copyFrom(getCurrentMessage()),重新获得了(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)消息,然后开启一个线程来处理。

(2)线程中首先判断消息参数arg1,进入”case WIFI_STATE_ENABLING”,调用setWifiState方法。该方法主要是用来设置电池使用统计中的wifi信息。然后会发出一个WIFI_STATE_CHANGED_ACTION广播。

(3)调用 WifiNative.loadDriver()方法加载wifi相关驱动,成功后发送CMD_LOAD_DRIVER_SUCCESS消息。该消息会在当前DriverLoadingState状态的processMessage方法中被处理。

(4)处理CMD_LOAD_DRIVER_SUCCESS消息

  1. case CMD_LOAD_DRIVER_SUCCESS:
  2. transitionTo(mDriverLoadedState);
  3. break;
  4. .....

状态切换到DriverLoadedState。

2.6 DriverLoadedState状态处理

处理WifiStateMachine::setWifiEnabled方法发出的CMD_START_SUPPLICANT消息(在此之前,该消息一直未被处理)。

  1. case CMD_START_SUPPLICANT:
  2.    ......
  3. if(mWifiNative.startSupplicant(mP2pSupported)) {
  4. if (DBG) log("Supplicant start successful");
  5. mWifiMonitor.startMonitoring();
  6. transitionTo(mSupplicantStartingState);
  7. }
  8. ......
  9. }

(1)启动wpa_supplicant:

调用startSupplicant方法启动。

(2)启动WifiMonitor监听

  1. startMonitoring
  2.  
  3. --->new MonitorThread().start()
  4.  
  5. --->MonitorThread::run
  6.  
  7. --->WifiMonitor::connectToSupplicant()
  8.  
  9. --->WifiNative::connectToSupplicant() [最多尝试5次]
  10.  
  11. ---> mStateMachine.sendMessage(SUP_CONNECTION_EVENT)

最后成功连接上wpa_supplicant后,发出SUP_CONNECTION_EVENT消息。

(3)切换到SupplicantStartingState状态

处理SUP_CONNECTION_EVENT消息:

  1. case WifiMonitor.SUP_CONNECTION_EVENT:
  2. if (DBG) log("Supplicant connection established");
  3. setWifiState(WIFI_STATE_ENABLED);
  4.    ......
  5. sendSupplicantConnectionChangedBroadcast(true);
  6. transitionTo(mDriverStartedState);
  7. break;
  8. ......

设置电池统计为enabled,发出WIFI_STATE_CHANGED_ACTION广播。这个广播会被wifi应用和状态栏接收处理;sendSupplicantConnectionChangedBroadcast方法发出广播,只在测试代码中被处理;最后切换到DriverStartedState状态。

到此为止,开机启动wifi的工作就完成了,over~~

-----------------------------------------------------------------

三、打开wifi,自动扫描AP

1. WifiSettings类构造函数:

(1)定义了一个广播;

(2)创建了一个Scanner对象(Scanner类是一个Handler子类,用来启动扫描功能)

2. WifiSettings::onActivityCreated

  1. ---->new WifiEnabler(...)
  2.  
  3. ---->WifiEnabler::resume()
  4.  
  5. ---->resume方法中,为Switch开关设置了checkedChange的监听方法。

3. 初始化相关类对象的工作已完成,现在打开wifi。

首先点击Switch开关,将触发onCheckedChanged方法。在这里,会先对飞行模式、wifi的状态进行判断。

  1. ---->WifiManger::setWifiEnabled
  2.  
  3. ---->WifiService::setWifiEnabled
  4.  
  5. ---->WifiStateMachine::setWifiEnabled
  6.  
  7. ---->接下来的操作同” 开机wifi功能启动”。直到开机wifi功能启动完毕。

此时,WifiStateMachine::SupplicantStartingState::processMessage:

  1. ---->case WifiMonitor.SUP_CONNECTION_EVENT:
  2.  
  3. setWifiState(WIFI_STATE_ENABLED); //wifi状态为enabled
  4.  
  5. ......

该方法会发送一个WIFI_STATE_CHANGED_ACTION的粘性广播。这个广播会被WifiSettings类接收到。

4. WifiSettings处理WIFI_STATE_CHANGED_ACTION广播

  1. BroadcastReceiver::onReceive
  2.  
  3. ---->handleEvent
  4.  
  5. ---->updateWifiState //在该方法中,接着会调用Scanner::resume方法。
  6.  
  7. ---->Scanner::resume
  8.  
  9. ---->Scanner::sendEmptyMessage(0)
  10.  
  11. ---->Scanner::handleMessage
  12.  
  13. 调用WifiManager::startScanActive方法进行扫描
  14.  
  15. ---->WifiManager::startScanActive
  16.  
  17. ---->WifiService::startScan
  18.  
  19. ---->WifiStateMachine::startScan //发出CMD_START_SCAN消息
  20.  
  21. 该消息会被DriverstartedState状态处理。
  22.  
  23. ---->WifiNative::scan

接着就调用到native层去了...这里就不分析下去了,等后面整体分析...

分析完毕,over~~

-----------------------------------------------------------------

四、打开wifi,连接AP

分成两个部分分析:

1.wifi ap 提示框的创建

2.输入密码,连接ap

1. wifi ap 提示框的创建

初始条件:这里分析安全性为加密的ap。

1.1 点击某个ap,调用流程:

  1. ---->WifiSettings::onPreferenceTreeClick
  2.  
  3. ---->WifiSettings::showDialog(选择的AP, false)
  4.  
  5. 接着调用父类的showDialog方法
  6.  
  7. ---->SettingsPreferenceFragment::showDialog(WIFI_DIALOG_ID) 

在SettingsPreferenceFragment类中,会创建一个SettingsDialogFragment对象,代码如下:

  1. protected void showDialog(int dialogId) {
  2. if (mDialogFragment != null) {
  3. Log.e(TAG, "Old dialog fragment not null!");
  4. }
  5. //创建一个SettingsDialogFragment对象
  6. mDialogFragment = new SettingsDialogFragment(this, dialogId); //(1)
  7. mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); //(2)
  8. }

(1) SettingsDialogFragment类继承自DialogFragment类,会在onCreate后调用onCreateDialog方法。

  1. ---->SettingsDialogFragment(DialogCreatable fragment, int dialogId)
  2.  
  3. ---->SettingsDialogFragment::onCreateDialog()

因为初始情况下,savedInstanceState为null,所以该方法直接回调构造函数中传入的fragment参数的onCreateDialog方法,即WifiSettings::onCreateDialog。

  1. ---->WifiSettings::onCreateDialog

回到WifiSettings类:

在WifiSettings::onCreateDialog方法中,会创建一个WifiDialog类对象。

跳转到WifiDialog类:

执行WifiDialog类的onCreate方法,会发现它创建了一个WifiConfigController类对象。

再看WifiConfigController类:

该类的构造函数主要是初始化了ap提示框的界面,当然还包括”添加网络”的界面。

这样,界面就创建了,需要显示出来,这就是下一步的作用了。

(2)调用了DialogFragment::show方法,将提示框显示出来。

至此,提示框分析完毕。

2. 输入密码,连接ap

(1)点击ap提示框的“连接”按钮,会调用WifiSettings::onClick方法:

  1. public void onClick(DialogInterface dialogInterface, int button) {
  2. if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
  3. forget();
  4. } else if (button == WifiDialog.BUTTON_SUBMIT) {
  5. if (FeatureQuery.FEATURE_CT_FMC_SUPPORT) {
  6. shouldShowErrorMsg = true;
  7. }
  8. submit(mDialog.getController());
  9. }
  10. }

(2) 接着便调用submit方法,参数为WifiConfigController类对象。

(3) submit方法中会调用WifiManager::connect方法进行连接。

over~~

-----------------------------------------------------------------

分析framework-->native-->wpa_supplicant几个方法的调用流程

  1. mWifiNative.isDriverLoaded()
  2.  
  3. ---> android_net_wifi_Wifi.cpp::android_net_wifi_isDriverLoaded
  4.  
  5. ---> wifi.c:: is_wifi_driver_loaded()
  6. --->查看系统属性wlan.driver.status(ok为已加载驱动,unloaded为未加载)
  1. mWifiNative.loadDriver()
  2.  
  3. ---> android_net_wifi_Wifi.cpp::android_net_wifi_loadDriver
  4.  
  5. ---> wifi.c:: wifi_load_driver()
  6.    ---> ensure_wlan_driver_config_file_exists
  7.       //首先判断wifi的驱动配置文件是否加载
  8. --->property_set //设置属性
  9. --->insmod //install modules 载入驱动模块等
  1. mWifiNative.startSupplicant(mP2pSupported)
  2. 参数为mP2pSupported,即是否支持p2p
  3.  
  4. ---> android_net_wifi_Wifi.cpp::android_net_wifi_startSupplicant
  5.  
  6. ---> wifi.c::wifi_start_supplicant(p2pSupported)
  7.    ---> ensure_config_file_exists
  8.       //首先判断wifi的配置文件是否加载
  9. "/data/misc/wifi/wpa_supplicant.conf";
  10. "/data/misc/wifi/p2p_supplicant.conf";
  11. --->property_set("ctl.start", supplicant_name);
  12.  // 这里supplicant_name为p2p_supplicant,所以就会启动init.rc中名为p2p_supplicant的服务了

ps:

property_set("ctl.start",xxx)

property_set("ctl.stop",xxx)

来使得android property service 去开启或结束 xxx service.

因为init.qcom.rc中service p2p_supplicant中已经包含了wpa_supplicant启动所需的语句及参数,所以后面会开始执行wpa_supplicant/main.c::main方法来初始化wpa_supplicant了。

wpa_supplicant初始化  见wpa_supplicant初始化

  1. WifiMonitor::connectToSupplicant
  2.  
  3. ---> mWifiNative.connectToSupplicant()
  4. ---> mWifiNative.connectToSupplicant(mInterface)
  5. //mInterface是创建WifiNative对象的时候传递进来的参数
  6.  
  7. ---> android_net_wifi_Wifi::android_net_wifi_connectToSupplicant
  8.  
  9. ---> wifi.c:: wifi_connect_to_supplicant(ifname.c_str())
  10.  
  11. ---> 首先判断文件IFACE_DIR = "/data/system/wpa_supplicant";是否存在,
  12.   存在:ifname="/data/system/wpa_supplicant/wlan0";
  13.    不存在:ifname=wlan0
  14.  
  15. ---> wifi_connect_on_socket_path
  16. /* 首先,判断系统属性:
  17.    * wlan.driver.status 是否为ok
  18.    * init.svc.p2p_supplicant 是否为running
  19.    * 然后,创建两个socket(通过wpa_ctrl_open方法)
  20.    * ctrl_conn:用于向wpa_supplicant发送命令并接收response
  21.    * monitor_conn:它一直阻塞等待从wpa_supplicant过来的event
  22.    * 最后调用wpa_ctrl_attach将monitor_conn信息注册到wpa_supplicant
  23.    */

wpa_ctrl_attach作用:由于socket是数据报方式的,这一步是必须的,对于存在于wpa_supplicant的服务器端,它是所有客户端共享的,由于它需要主动向monitor_conn客户端发送事件,所以它必须先记录下该客户端的详细信息,wpa_supplicant就可以将event发向该socket。

这样,就通过socket,建立起native-->wpa_supplicant的连接了。

  1. mWifiNative.waitForEvent()
  2. 该函数是有返回值的,返回值即为wpa_supplicant传递过来的消息。
  3.  
  4. java层会通过jni方式调用android_net_wifi_waitForEvent(在线程MonitorThread中调用)方法,该方法会调用wifi_wait_for_event。在wifi_wait_for_event方法里,会阻塞接收从wpa_supplicant模块传来的事件,一旦wpa_supplicant模块发出事件,wifi_wait_for_event接收到后,会将包含事件的buf通过函数参数的方式回传到java层,java收到事件后,再继续调用wifi_wait_for_event函数进行阻塞等待接收,从而完成一个循环。
  5.  
  6. ---> mWifiNative::waitForEvent(mInterface)
  7.  
  8. ---> android_net_wifi_Wifi.cpp::android_net_wifi_waitForEvent
  9.  
  10. ---> wifi.c::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf)
  11.   ---> wifi_wait_on_socket
  12.   ---> wifi_ctrl_recv
  13.   ---> wpa_ctrl_recv
  14.   ---> recv
  15. ps:从wpa_supplicant传递过来的值由recv函数接收,一直向上传递到buf参数中,最终返回return env->NewStringUTF(buf)给WifiMonitor

android4.1 Wifi 浅析的更多相关文章

  1. Wifi开发技术总结1

    摘要: 刚刚接触wifi开发的东西,用的模块是 ESP8266-12E. 资料很多,淘宝地址:https://item.taobao.com/item.htm?spm=a1z09.2.9.10.qGL ...

  2. 4412 SPI驱动

    1.Linux主机驱动和外设驱动分离思想(I2C驱动里有) SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√).前面两个设备驱动搞明白了可以去看 2.教程中介绍: ...

  3. Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

    源: Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

  4. 无线局域网络 WIFI/WAPI/WLAN区别浅析

    WIFI和WAPI的区别 既然WIFI和WAPI都是WLAN的传输协议,那么两者究竟都有怎样的区别? 首先第一点区别在于,两者的缔造者不一样.WIFI是又国外制定的一个协议,而WAPI是由中国制定的, ...

  5. 浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制

    libs/android_runtime/android_net_wifi_Wifi.cpp部分jni接口static JNINativeMethod gWifiMethods[] = {{ &quo ...

  6. 解决WIFI驱动RTL8188无法在rk3168平板Android4.2启动wifi的问题

    http://blog.csdn.net/morixinguan/article/details/75228335 上一篇博文能把ko编译出来,非常兴奋的想,这一定是没问题了,结果删除原先的ko后,加 ...

  7. Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析

    SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈.可以实现用户主平台数据通过SDIO口到无线网络之间的转 ...

  8. android4.0.3源码之USB wifi移植心得

    http://blog.csdn.net/eastmoon502136/article/details/7850157 http://forum.cubietech.com/forum.php?mod ...

  9. (转) 浅析HTML5在移动应用开发中的使用

    (转)浅析HTML5在移动应用开发中的使用 (原)http://www.iteye.com/magazines/67   2012-03-07  来自 UECD.163.com  编辑 wangguo ...

随机推荐

  1. html基础用法(下)

    设计表格: <html> <head> <title>表格</title> <meta charset="utf-8" /&g ...

  2. 终于好像懂motan了!!!

    我依稀记得,刚到公司的时候,锋哥让我学习Maven,spring,spring MVC,mybatis,RPC:motan,Xdiamond,Jenkins,redis和Kafka.快3个月了,目前只 ...

  3. Unity 游戏框架搭建 (九) 减少加班利器-QConsole

    为毛要实现这个工具? 在我小时候,每当游戏在真机运行时,我们看到的日志是这样的. 没高亮啊,还有乱七八糟的堆栈信息,好干扰日志查看,好影响心情. 还有就是必须始终连着usb线啊,我想要想躺着测试... ...

  4. jquery mobile 移动web(2)

    button 按钮 data-role="button" 将超链接变成button. 具有icon 图标的button 组件. 提供了18常用的图标 data-icon =&quo ...

  5. MySQL备份恢复之mysqldump

      Preface       The day before yesterday,there's a motif about the lock procedure when backing up My ...

  6. 关系型数据库设计——E-R图

    一.数据管理技术的三个发展阶段: 1)人工管理阶段(20世纪50年代中期) 特点:数据不保存:应用程序管理数据:数据不共享:数据没有独立性: 2)文件系统阶段(20世纪50年代后—60年代)特点:数据 ...

  7. sql sever 基础 建表

    ---恢复内容开始--- SQL Sever 基础以创建银行数据库bankDB为案例 1.创建数据库 1-1 创建文件夹用以存放数据库 1-2 创建建库bankDB 2.创建数据库 2-1.创建用户信 ...

  8. 分布式日志系统ELK搭建

    ELK:Elasticsearch  Logstash Kibana Elasticsearch:是基于JSON的分布式搜索和分析引擎,专为实现水平扩展.高可用和管理便捷性而设计 Logstash:是 ...

  9. vue组件中的样式属性--scoped

    Scoped CSS Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范. vue组件中的style标签标有scoped属性时表明style里的css样式只适用于当 ...

  10. nodeJs 对 Mysql 数据库的 curd

    var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : ' ...