android4.1 Wifi 浅析
简单分析下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 相关文件
framework
WifiManager
管理所有wifi操作,提供API调用,主要用于上层应用调用
WifiService
处理Wifi操作请求。一般都是在WifiManager中被调用
WifiStateMachine
处理wifi各个阶段状态所要处理的消息
WifiMonitor
监听所有来自wpa_supplicant的事件,并传递给WifiStateMachine处理
WifiNative
native方法,发送消息给wpa_supplicant jni层
android_net_wifi_Wifi.cpp wpa_supplicant适配器层
wifi.c wpa_supplicant层
wpa_supplicant.c
接下来分析wifi启动、扫描、连接ap的流程。
一、 Wifi相关类创建
1.SystemServer::ServerThread::run---->new WifiService(...); 2.WifiService(...)---->new WifiStateMachine(...); 3.WifiStateMachine(...) ---->new WifiNative(...) ---->new WifiMonitor(...) ---->AsyncChannel::connectSync(...) ps: AsyncChannel::connectSync将WifiStateMachine和wifiApConfigStore通过AsyncChannel关联起来。 4. SystemServer::ServerThread::run ServiceManager.addService(...);
over~~
-----------------------------------------------------------------
二、 wifi功能启动
先贴出整体流程时序图
1. 检查系统属性中的wifi状态信息
SystemServer::ServerThread::run
--->WifiService::checkAndStartWifi (该方法只在开机时调用,用来检查wifi是否需要开启)
分析WifiService::checkAndStartWifi方法:
public void checkAndStartWifi() {
mAirplaneModeOn.set(isAirplaneModeOn());
mPersistWifiState.set(getPersistedWifiState());
/* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled")); // If we are already disabled (could be due to airplane mode), avoid changing persist
// state here
if (wifiEnabled) setWifiEnabled(wifiEnabled); mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
makeWifiWatchdogStateMachine(mContext); //以后分析 }
(1)isAirplaneModeOn()/getPersistedWifiState():都是获取系统属性进行判断。
(2)shouldWifiBeEnabled():判断mAirplaneModeOn/mPersistWifiState中的值,其实就是上述两个方法获得的值。
(3)testAndClearWifiSavedState():获取系统属性中保存的wifi状态的值,返回,之后清空状态,置为0。
另注意:以下分析都是基于条件:开机启动时,wifi状态为on。
因此,接着会调用setWifiEnabled(true)方法,下面分析。
到此,检查wifi系统属性状态的操作结束,over~~
2.setWifiEnabled(true)执行流程
2.1
该方法中主要执行以下语句:
if (FeatureQuery.FEATURE_CT_FMC_SUPPORT && WifiManager.fmcV2Support()) {
mWifiStateMachine.fmcV2SetWifiEnabled(enable);
} else {
mWifiStateMachine.setWifiEnabled(enable);
}
分析:
FeatureQuery.FEATURE_CT_FMC_SUPPORT/WifiManager.fmcV2Support()
(1)FeatureQuery.FEATURE_CT_FMC_SUPPORT
这个属性值在build/buildplus/target/FeatureQuery.java里可以找到。
(2)WifiManager::fmcV2Support方法如下:
public static boolean fmcV2Support() {
return (SystemProperties.getInt("ro.config.cwenable", 0) == 1)
&& (SystemProperties.getInt("ro.config.fmcv2support", 0) == 1);
}
就是获取两个系统属性,判断是否支持FMC功能,有两种方式可以查看
(a)在out/target/product/msm8625/system/build.prop中可以找到
(b)命令提示符下,adb shell,然后使用命令:getprop XX ,就可以获得属性值。XX表示系统属性名。
总结:这两个条件的作用就是判断是否支持FMC功能(固定网络与移动网络融合)。
2.2
执行mWifiStateMachine.fmcV2SetWifiEnabled方法:
public void fmcV2SetWifiEnabled(boolean enable) {
if (!enable) {
......
} else {
setWifiEnabled(enable);
}
}
接着调用WifiStateMachine::setWifiEnabled(enable)方法: 发送两个消息。
public void setWifiEnabled(boolean enable) {
mLastEnableUid.set(Binder.getCallingUid());
if (enable) {
/* Argument is the state that is entered prior to load */
sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
sendMessage(CMD_START_SUPPLICANT);
} else {
......
}
}
接收CMD_LOAD_DRIVER消息的是DriverUnloadedState状态。
2.4 DriverUnloadedState状态处理
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
switch (message.what) {
case CMD_LOAD_DRIVER:
transitionTo(mDriverLoadingState);
break;
......
}
在这里CMD_LOAD_DRIVER消息被处理,切换到DriverLoadingState状态。
2.5 DriverLoadingState 处理状态
public void enter() {
......
final Message message = new Message();
message.copyFrom(getCurrentMessage());
new Thread(new Runnable() {
public void run() {
mWakeLock.acquire();
//enabling state
switch(message.arg1) {
case WIFI_STATE_ENABLING:
setWifiState(WIFI_STATE_ENABLING);
break;
case WIFI_AP_STATE_ENABLING:
setWifiApState(WIFI_AP_STATE_ENABLING);
break;
} if(mWifiNative.loadDriver()) {
if (DBG) log("Driver load successful");
sendMessage(CMD_LOAD_DRIVER_SUCCESS);
}
.....
}
(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消息
case CMD_LOAD_DRIVER_SUCCESS:
transitionTo(mDriverLoadedState);
break;
.....
状态切换到DriverLoadedState。
2.6 DriverLoadedState状态处理
处理WifiStateMachine::setWifiEnabled方法发出的CMD_START_SUPPLICANT消息(在此之前,该消息一直未被处理)。
case CMD_START_SUPPLICANT:
......
if(mWifiNative.startSupplicant(mP2pSupported)) {
if (DBG) log("Supplicant start successful");
mWifiMonitor.startMonitoring();
transitionTo(mSupplicantStartingState);
}
......
}
(1)启动wpa_supplicant:
调用startSupplicant方法启动。
(2)启动WifiMonitor监听
startMonitoring --->new MonitorThread().start() --->MonitorThread::run --->WifiMonitor::connectToSupplicant() --->WifiNative::connectToSupplicant() [最多尝试5次] ---> mStateMachine.sendMessage(SUP_CONNECTION_EVENT)
最后成功连接上wpa_supplicant后,发出SUP_CONNECTION_EVENT消息。
(3)切换到SupplicantStartingState状态
处理SUP_CONNECTION_EVENT消息:
case WifiMonitor.SUP_CONNECTION_EVENT:
if (DBG) log("Supplicant connection established");
setWifiState(WIFI_STATE_ENABLED);
......
sendSupplicantConnectionChangedBroadcast(true);
transitionTo(mDriverStartedState);
break;
......
设置电池统计为enabled,发出WIFI_STATE_CHANGED_ACTION广播。这个广播会被wifi应用和状态栏接收处理;sendSupplicantConnectionChangedBroadcast方法发出广播,只在测试代码中被处理;最后切换到DriverStartedState状态。
到此为止,开机启动wifi的工作就完成了,over~~
-----------------------------------------------------------------
三、打开wifi,自动扫描AP
1. WifiSettings类构造函数:
(1)定义了一个广播;
(2)创建了一个Scanner对象(Scanner类是一个Handler子类,用来启动扫描功能)
2. WifiSettings::onActivityCreated
---->new WifiEnabler(...) ---->WifiEnabler::resume() ---->resume方法中,为Switch开关设置了checkedChange的监听方法。
3. 初始化相关类对象的工作已完成,现在打开wifi。
首先点击Switch开关,将触发onCheckedChanged方法。在这里,会先对飞行模式、wifi的状态进行判断。
---->WifiManger::setWifiEnabled ---->WifiService::setWifiEnabled ---->WifiStateMachine::setWifiEnabled ---->接下来的操作同” 开机wifi功能启动”。直到开机wifi功能启动完毕。
此时,WifiStateMachine::SupplicantStartingState::processMessage:
---->case WifiMonitor.SUP_CONNECTION_EVENT: setWifiState(WIFI_STATE_ENABLED); //wifi状态为enabled ......
该方法会发送一个WIFI_STATE_CHANGED_ACTION的粘性广播。这个广播会被WifiSettings类接收到。
4. WifiSettings处理WIFI_STATE_CHANGED_ACTION广播
BroadcastReceiver::onReceive ---->handleEvent ---->updateWifiState //在该方法中,接着会调用Scanner::resume方法。 ---->Scanner::resume ---->Scanner::sendEmptyMessage(0) ---->Scanner::handleMessage 调用WifiManager::startScanActive方法进行扫描 ---->WifiManager::startScanActive ---->WifiService::startScan ---->WifiStateMachine::startScan //发出CMD_START_SCAN消息 该消息会被DriverstartedState状态处理。 ---->WifiNative::scan
接着就调用到native层去了...这里就不分析下去了,等后面整体分析...
分析完毕,over~~
-----------------------------------------------------------------
四、打开wifi,连接AP
分成两个部分分析:
1.wifi ap 提示框的创建
2.输入密码,连接ap
1. wifi ap 提示框的创建
初始条件:这里分析安全性为加密的ap。
1.1 点击某个ap,调用流程:
---->WifiSettings::onPreferenceTreeClick ---->WifiSettings::showDialog(选择的AP, false) 接着调用父类的showDialog方法 ---->SettingsPreferenceFragment::showDialog(WIFI_DIALOG_ID)
在SettingsPreferenceFragment类中,会创建一个SettingsDialogFragment对象,代码如下:
protected void showDialog(int dialogId) {
if (mDialogFragment != null) {
Log.e(TAG, "Old dialog fragment not null!");
}
//创建一个SettingsDialogFragment对象
mDialogFragment = new SettingsDialogFragment(this, dialogId); //(1)
mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); //(2)
}
(1) SettingsDialogFragment类继承自DialogFragment类,会在onCreate后调用onCreateDialog方法。
---->SettingsDialogFragment(DialogCreatable fragment, int dialogId) ---->SettingsDialogFragment::onCreateDialog()
因为初始情况下,savedInstanceState为null,所以该方法直接回调构造函数中传入的fragment参数的onCreateDialog方法,即WifiSettings::onCreateDialog。
---->WifiSettings::onCreateDialog
回到WifiSettings类:
在WifiSettings::onCreateDialog方法中,会创建一个WifiDialog类对象。
跳转到WifiDialog类:
执行WifiDialog类的onCreate方法,会发现它创建了一个WifiConfigController类对象。
再看WifiConfigController类:
该类的构造函数主要是初始化了ap提示框的界面,当然还包括”添加网络”的界面。
这样,界面就创建了,需要显示出来,这就是下一步的作用了。
(2)调用了DialogFragment::show方法,将提示框显示出来。
至此,提示框分析完毕。
2. 输入密码,连接ap
(1)点击ap提示框的“连接”按钮,会调用WifiSettings::onClick方法:
public void onClick(DialogInterface dialogInterface, int button) {
if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
forget();
} else if (button == WifiDialog.BUTTON_SUBMIT) {
if (FeatureQuery.FEATURE_CT_FMC_SUPPORT) {
shouldShowErrorMsg = true;
}
submit(mDialog.getController());
}
}
(2) 接着便调用submit方法,参数为WifiConfigController类对象。
(3) submit方法中会调用WifiManager::connect方法进行连接。
over~~
-----------------------------------------------------------------
分析framework-->native-->wpa_supplicant几个方法的调用流程
mWifiNative.isDriverLoaded() ---> android_net_wifi_Wifi.cpp::android_net_wifi_isDriverLoaded ---> wifi.c:: is_wifi_driver_loaded()
--->查看系统属性wlan.driver.status(ok为已加载驱动,unloaded为未加载)
mWifiNative.loadDriver() ---> android_net_wifi_Wifi.cpp::android_net_wifi_loadDriver ---> wifi.c:: wifi_load_driver()
---> ensure_wlan_driver_config_file_exists
//首先判断wifi的驱动配置文件是否加载
--->property_set //设置属性
--->insmod //install modules 载入驱动模块等
mWifiNative.startSupplicant(mP2pSupported)
参数为mP2pSupported,即是否支持p2p ---> android_net_wifi_Wifi.cpp::android_net_wifi_startSupplicant ---> wifi.c::wifi_start_supplicant(p2pSupported)
---> ensure_config_file_exists
//首先判断wifi的配置文件是否加载
"/data/misc/wifi/wpa_supplicant.conf";
"/data/misc/wifi/p2p_supplicant.conf";
--->property_set("ctl.start", supplicant_name);
// 这里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初始化
WifiMonitor::connectToSupplicant ---> mWifiNative.connectToSupplicant()
---> mWifiNative.connectToSupplicant(mInterface)
//mInterface是创建WifiNative对象的时候传递进来的参数 ---> android_net_wifi_Wifi::android_net_wifi_connectToSupplicant ---> wifi.c:: wifi_connect_to_supplicant(ifname.c_str()) ---> 首先判断文件IFACE_DIR = "/data/system/wpa_supplicant";是否存在,
存在:ifname="/data/system/wpa_supplicant/wlan0";
不存在:ifname=wlan0 ---> wifi_connect_on_socket_path
/* 首先,判断系统属性:
* wlan.driver.status 是否为ok
* init.svc.p2p_supplicant 是否为running
* 然后,创建两个socket(通过wpa_ctrl_open方法)
* ctrl_conn:用于向wpa_supplicant发送命令并接收response
* monitor_conn:它一直阻塞等待从wpa_supplicant过来的event
* 最后调用wpa_ctrl_attach将monitor_conn信息注册到wpa_supplicant
*/
wpa_ctrl_attach作用:由于socket是数据报方式的,这一步是必须的,对于存在于wpa_supplicant的服务器端,它是所有客户端共享的,由于它需要主动向monitor_conn客户端发送事件,所以它必须先记录下该客户端的详细信息,wpa_supplicant就可以将event发向该socket。
这样,就通过socket,建立起native-->wpa_supplicant的连接了。
mWifiNative.waitForEvent()
该函数是有返回值的,返回值即为wpa_supplicant传递过来的消息。 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函数进行阻塞等待接收,从而完成一个循环。 ---> mWifiNative::waitForEvent(mInterface) ---> android_net_wifi_Wifi.cpp::android_net_wifi_waitForEvent ---> wifi.c::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf)
---> wifi_wait_on_socket
---> wifi_ctrl_recv
---> wpa_ctrl_recv
---> recv
ps:从wpa_supplicant传递过来的值由recv函数接收,一直向上传递到buf参数中,最终返回return env->NewStringUTF(buf)给WifiMonitor。
android4.1 Wifi 浅析的更多相关文章
- Wifi开发技术总结1
摘要: 刚刚接触wifi开发的东西,用的模块是 ESP8266-12E. 资料很多,淘宝地址:https://item.taobao.com/item.htm?spm=a1z09.2.9.10.qGL ...
- 4412 SPI驱动
1.Linux主机驱动和外设驱动分离思想(I2C驱动里有) SPI驱动总线架构:SPI核心层(x),SPI控制器驱动层(x),SPI设备驱动层(√).前面两个设备驱动搞明白了可以去看 2.教程中介绍: ...
- Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
源: Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
- 无线局域网络 WIFI/WAPI/WLAN区别浅析
WIFI和WAPI的区别 既然WIFI和WAPI都是WLAN的传输协议,那么两者究竟都有怎样的区别? 首先第一点区别在于,两者的缔造者不一样.WIFI是又国外制定的一个协议,而WAPI是由中国制定的, ...
- 浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制
libs/android_runtime/android_net_wifi_Wifi.cpp部分jni接口static JNINativeMethod gWifiMethods[] = {{ &quo ...
- 解决WIFI驱动RTL8188无法在rk3168平板Android4.2启动wifi的问题
http://blog.csdn.net/morixinguan/article/details/75228335 上一篇博文能把ko编译出来,非常兴奋的想,这一定是没问题了,结果删除原先的ko后,加 ...
- Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析
SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈.可以实现用户主平台数据通过SDIO口到无线网络之间的转 ...
- android4.0.3源码之USB wifi移植心得
http://blog.csdn.net/eastmoon502136/article/details/7850157 http://forum.cubietech.com/forum.php?mod ...
- (转) 浅析HTML5在移动应用开发中的使用
(转)浅析HTML5在移动应用开发中的使用 (原)http://www.iteye.com/magazines/67 2012-03-07 来自 UECD.163.com 编辑 wangguo ...
随机推荐
- Object Detection with Discriminatively Trained Part Based Models
P. Felzenszwalb, R. Girshick, D. McAllester, D. RamananObject Detection with Discriminatively Traine ...
- Struts2 第四讲 -- Struts2的基本配置
5.struts2的基本配置 5.1 struts2的访问连接url 在struts1中,通过<action path=“/primer/helloWorldAction.action”> ...
- 有连接服务&无连接服务
面向连接的服务 通信双方在通信时要事先建立一条通信线路,其过程包括建立连接.使用链接.释放链接三个过程 如: TCP 电话 面向无连接的服务 通信双方不需要事先建立一条通信线路,而是把每个带有目的选址 ...
- 微信小程序学习笔记(一)
1.目录及文件构成 1.1 根目录下 ** app.js 是小程序的脚本代码,用来监听并处理小程序的生命周期函数.声明全局变量. ** app.json 是对整个小程序的全局配置,配置小程序是由哪些页 ...
- dropload上拉加载更多
<link href="~/Scripts/dropload/dropload.min.css" rel="stylesheet" /> <s ...
- #leetcode刷题之路3-无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1:输入: "abcabcbb"输出: 3 解释: 因为无重复字符的最长子串是 "abc" ...
- Percona-Tookit工具包之pt-visual-explain
Preface As usual we will check the MySQL executed plan of SQL query by execute "explain ...
- Struts2的动态方法,及result跳转方式,全局结果以及默认的action的配置
Action动态方法的调用 首先我们需要在struts.xml中去配置一个常量值如下 那么去哪找呢?找到Struts-core.jar并打开 method属性 <action name=&quo ...
- 微信小程序播放视频
<view class="section tc"> <video id="myVideo" src="http://wxsnsdy. ...
- ABAP CDS ON HANA-(7)CDSビューでの集約
Aggregate expression in CDS View An aggregate expression calculates a single value from an operand o ...