声明:本文纯属网上资料收集,版权归源作者所有,转载时请标明为转载文章

现在对android平台的wifi模块了解了一段时间,现在做一些简要总结,以便以后查阅和与修正,上正文。

【Wifi模块学习流程】

最近研究Wifi模块,查了不少的相关资料,但发现基本上是基于android2.0版本的的分析,而现在研发的android移动平台基本上都是2.3的版本,跟2.0版本的差别,在Wifi模块上也是显而易见的。2.3版本Wifi模块没有了WifiLayer,之前的WifiLayer主要负责一些复杂的Wifi功能,如AP选择等以提供给用户自定义,而新的版本里面的这块内容基本上被WifiSettings所代替

本文就是基于android2.3版本的Wifi分析,主要分为两部分来分别说明:

(a)    Wifi的启动流程(有代码供参考分析)

(b)    Wifi模块相关文件的解析

(c)    Wpa_supplicant解析

【A】wifi的基本运行流程(针对代码而言)

首先给一张我网上down下来的图,针对2.3版本之前的,由于不怎么擅长画这些,大家也就将就点,只要能助理解就可以了

(一)初始化

a.流程

1.在SystemServer启动的时候会生成一个ConnectivityService的实例

2.ConnectivityService的构造函数会创建WifiService

3.WifiStateTracker会创建WifiMonitor接受来自底层的事件,WifiService和WifiMonitor是整个wifi模块的核心,WifiService负责启动和关闭wpa_supplicant,启动和关闭WifiMonitor监视线程和把命令下方给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接受事件通知

b.代码分析

要想使用Wifi模块,必须首先使能Wifi,当你第一次按下Wifi使能按钮时,WirelessSettings会实例化一个WifiEnabler对象,实例化代码如下:

packages/apps/settings/src/com/android/settings/WirelessSettings.java

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
……CheckBoxPreferencewifi = (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI);mWifiEnabler= new WifiEnabler(this, wifi);
……
}

WifiEnabler类的定义大致如下,它实现了一个监听接口,当WifiEnabler对象被初始化后,它监听到你按键的动作,会调用响应函数 onPreferenceChange(),这个函数会调用WifiManager的setWifiEnabled()函数。

public class WifiEnabler implementsPreference.OnPreferenceChangeListener {……public boolean onPreferenceChange(Preference preference,Object value) {booleanenable = (Boolean) value;……if (mWifiManager.setWifiEnabled(enable)) {mCheckBox.setEnabled(false);
……
}……}

我们都知道Wifimanager只是个服务代理,所以它会调用WifiService的setWifiEnabled()函数,而这个函数会调用 sendEnableMessage()函数,了解android消息处理机制的都知道,这个函数最终会给自己发送一个 MESSAGE_ENABLE_WIFI的消息,被WifiService里面定义的handlermessage()函数处理,会调用 setWifiEnabledBlocking()函数。下面是调用流程:

mWifiEnabler.onpreferencechange()===>mWifiManage.setWifienabled()===>mWifiService.setWifiEnabled()===>mWifiService.sendEnableMessage()

===>mWifiService.handleMessage()===>mWifiService.setWifiEnabledBlocking().

在setWifiEnabledBlocking()函数中主要做如下工作:加载Wifi驱动,启动wpa_supplicant,注册广播接收器,启动WifiThread监听线程。代码如下:

……if (enable) {if (!mWifiStateTracker.loadDriver()) {Slog.e(TAG, "Failed toload Wi-Fi driver.");setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);return false;}if (!mWifiStateTracker.startSupplicant()) {mWifiStateTracker.unloadDriver();Slog.e(TAG, "Failed tostart supplicant daemon.");setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);return false;}registerForBroadcasts();mWifiStateTracker.startEventLoop();……

至此,Wifi使能(开启)结束,自动进入扫描阶段。

(二)扫描AP

当驱动加载成功后,如果配置文件的AP_SCAN = 1,扫描会自动开始,WifiMonitor将会从supplicant收到一个消息EVENT_DRIVER_STATE_CHANGED,调用 handleDriverEvent(),然后调用mWifiStateTracker.notifyDriverStarted(),该函数向消息队列添加EVENT_DRIVER_STATE_CHANGED,handlermessage()函数处理消息时调用scan()函数,并通过 WifiNative将扫描命令发送到wpa_supplicant。

看代码Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

private void handleDriverEvent(Stringstate) {if (state == null) {return;}if (state.equals("STOPPED")) {mWifiStateTracker.notifyDriverStopped();} else if (state.equals("STARTED")) {mWifiStateTracker.notifyDriverStarted();} else if (state.equals("HANGED")) {mWifiStateTracker.notifyDriverHung();}}

Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

...
case EVENT_DRIVER_STATE_CHANGED:switch(msg.arg1) {case DRIVER_STARTED:/***Set the number of allowed radio channels according*to the system setting, since it gets reset by the*driver upon changing to the STARTED state.*/setNumAllowedChannels();synchronized (this) {if (mRunState == RUN_STATE_STARTING) {mRunState = RUN_STATE_RUNNING;if (!mIsScanOnly) {reconnectCommand();} else {// In somesituations, supplicant needs to be kickstarted to// start thebackground scanningscan(true);}}}break;
...

上面是启动Wifi时,自动进行的AP的扫描,用户当然也可以手动扫描AP,这部分实现在WifiService里面,WifiService通过startScan()接口函数发送扫描命令到supplicant。

看代码:Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

public boolean startScan(booleanforceActive) {enforceChangePermission();switch (mWifiStateTracker.getSupplicantState()) {case DISCONNECTED:case INACTIVE:case SCANNING:case DORMANT:break;default:mWifiStateTracker.setScanResultHandling(WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);break;}return mWifiStateTracker.scan(forceActive);}

然后下面的流程同上面的自动扫描,我们来分析一下手动扫描从哪里开始的。我们应该知道手动扫描是通过菜单键的扫描键来响应的,而响应该动作的应该是 WifiSettings类中Scanner类的handlerMessage()函数,它调用WifiManager的 startScanActive(),这才调用WifiService的startScan()。

如代码:packages/apps/Settings/src/com/android/settings/wifiwifisettings.java

public boolean onCreateOptionsMenu(Menu menu) {menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.wifi_menu_scan).setIcon(R.drawable.ic_menu_scan_network);menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced).setIcon(android.R.drawable.ic_menu_manage);return super.onCreateOptionsMenu(menu);}

当按下菜单键时,WifiSettings就会调用这个函数绘制菜单。如果选择扫描按钮,WifiSettings会调用onOptionsItemSelected()。

packages/apps/Settings/src/com/android/settings/wifiwifisettings.java

public booleanonOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case MENU_ID_SCAN:if(mWifiManager.isWifiEnabled()) {mScanner.resume();}return true;case MENU_ID_ADVANCED:startActivity(new Intent(this,AdvancedSettings.class));return true;}return super.onOptionsItemSelected(item);}

Handler类:

private class Scanner extends Handler {private int mRetry = 0;void resume() {if (!hasMessages(0)) {sendEmptyMessage(0);}}void pause() {mRetry = 0;mAccessPoints.setProgress(false);removeMessages(0);}@Overridepublic void handleMessage(Message message) {if (mWifiManager.startScanActive()){mRetry = 0;} else if (++mRetry >= 3) {mRetry = 0;Toast.makeText(WifiSettings.this, R.string.wifi_fail_to_scan,Toast.LENGTH_LONG).show();return;}mAccessPoints.setProgress(mRetry != 0);sendEmptyMessageDelayed(0, 6000);}}

这里的mWifiManager.startScanActive()就会调用WifiService里的startScan()函数,下面的流程和上面的一样,这里不赘述。

当supplicant完成了这个扫描命令后,它会发送一个消息给上层,提醒他们扫描已经完成,WifiMonitor会接收到这消息,然后再发送给WifiStateTracker。

Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

void handleEvent(int event, String remainder) {switch (event) {caseDISCONNECTED:handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);break;case CONNECTED:handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);break;case SCAN_RESULTS:mWifiStateTracker.notifyScanResultsAvailable();break;case UNKNOWN:break;}}

WifiStateTracker将会广播SCAN_RESULTS_AVAILABLE_ACTION消息:

代码如:Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

public voidhandleMessage(Message msg) {Intent intent;……case EVENT_SCAN_RESULTS_AVAILABLE:if(ActivityManagerNative.isSystemReady()) {mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));}sendScanResultsAvailable();/*** On receiving the first scanresults after connecting to* the supplicant, switch scanmode over to passive.*/setScanMode(false);break;……}

由于WifiSettings类注册了intent,能够处理SCAN_RESULTS_AVAILABLE_ACTION消息,它会调用handleEvent(),调用流程如下所示。

WifiSettings.handleEvent() ====>WifiSettings.updateAccessPoints() ====> mWifiManager.getScanResults()====> mService.getScanResults()====> mWifiStateTracker.scanResults() ====> WifiNative.scanResultsCommand()……
将获取AP列表的命令发送到supplicant,然后supplicant通过Socket发送扫描结果,由上层接收并显示。这和前面的消息获取流程基本相同。

(3)配置,连接AP
当用户选择一个活跃的AP时,WifiSettings响应打开一个对话框来配置AP,比如加密方法和连接AP的验证模式。配置好AP后,WifiService添加或更新网络连接到特定的AP。
代码如:packages/apps/settings/src/com/android/settings/wifi/WifiSetttings.java

public booleanonPreferenceTreeClick(PreferenceScreen screen, Preference preference) {if (preference instanceof AccessPoint) {mSelected = (AccessPoint) preference;showDialog(mSelected, false);} else if (preference == mAddNetwork) {mSelected = null;showDialog(null, true);} else if (preference == mNotifyOpenNetworks) {Secure.putInt(getContentResolver(),Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,mNotifyOpenNetworks.isChecked() ? 1 : 0);} else {return super.onPreferenceTreeClick(screen, preference);}return true;}

配置好以后,当按下“Connect Press”时,WifiSettings通过发送LIST_NETWORK命令到supplicant来检查该网络是否配置。如果没有该网络或没有配置它,WifiService调用addorUpdateNetwork()函数来添加或更新网络,然后发送命令给supplicant,连接到这个网络。下面是从响应连接按钮到WifiService发送连接命令的代码:

packages/apps/settings/src/com/android/settings/wifi/WifiSetttings.java

public void onClick(DialogInterfacedialogInterface, int button) {if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {forget(mSelected.networkId);} else if (button == WifiDialog.BUTTON_SUBMIT && mDialog !=null) {WifiConfiguration config = mDialog.getConfig();if (config == null) {if (mSelected != null&& !requireKeyStore(mSelected.getConfig())) {connect(mSelected.networkId);}} else if (config.networkId != -1) {if (mSelected != null) {mWifiManager.updateNetwork(config);saveNetworks();}} else {int networkId =mWifiManager.addNetwork(config);if (networkId != -1) {mWifiManager.enableNetwork(networkId, false);config.networkId =networkId;if (mDialog.edit || requireKeyStore(config)){saveNetworks();} else {connect(networkId);}}}}
}

Frameworks\base\wifi\java\android\net\wifi\WifiManager.java

public intupdateNetwork(WifiConfiguration config) {if(config == null || config.networkId < 0) {return -1;}return addOrUpdateNetwork(config);}private intaddOrUpdateNetwork(WifiConfiguration config) {try {return mService.addOrUpdateNetwork(config);} catch (RemoteException e) {return -1;}}

WifiService.addOrUpdateNetwork()通过调用mWifiStateTracker.setNetworkVariable()将连接命令发送到Wpa_supplicant。

(4)获取IP地址
当连接到supplicant后,WifiMonitor就会通知WifiStateTracker。

代码如:Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

Public void Run(){if (connectToSupplicant()) {// Send a message indicatingthat it is now possible to send commands// to the supplicantmWifiStateTracker.notifySupplicantConnection();} else {mWifiStateTracker.notifySupplicantLost();return;}……}

WifiStateTracker发送EVENT_SUPPLICANT_CONNECTION消息到消息队列,这个消息有自己的handlermessage()函数处理,它会启动一个DHCP线程,而这个线程会一直等待一个消息事件,来启动DHCP协议分配IP地址。

frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

void notifySupplicantConnection() {sendEmptyMessage(EVENT_SUPPLICANT_CONNECTION);}public void handleMessage(Message msg) {Intent intent;switch (msg.what) {case EVENT_SUPPLICANT_CONNECTION:……HandlerThread dhcpThread = newHandlerThread("DHCP Handler Thread");dhcpThread.start();mDhcpTarget = newDhcpHandler(dhcpThread.getLooper(), this);…………
           case EVENT_NETWORK_STATE_CHANGED:……configureInterface();……
}}
private void configureInterface() {checkPollTimer();mLastSignalLevel = -1;if(!mUseStaticIp) {          //使用DHCP线程动态IPif(!mHaveIpAddress && !mObtainingIpAddress) {mObtainingIpAddress = true;//发送启动DHCP线程获取IPmDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);}} else {        //使用静态IP,IP信息从mDhcpInfo中获取intevent;if(NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {mHaveIpAddress = true;event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;if (LOCAL_LOGD) Log.v(TAG, "Static IP configurationsucceeded");}else {mHaveIpAddress = false;event = EVENT_INTERFACE_CONFIGURATION_FAILED;if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");}sendEmptyMessage(event);           //发送IP获得成功消息事件}}

当Wpa_supplicant连接到AP后,它会发送一个消息给上层来通知连接成功,WifiMonitor会接受到这个消息并上报给WifiStateTracker。
Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java
void handleEvent(int event, String remainder) {switch (event) {case DISCONNECTED:handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);break;case CONNECTED:handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);break;……}private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {StringBSSID = null;intnetworkId = -1;if(newState == NetworkInfo.DetailedState.CONNECTED) {Matcher match = mConnectedEventPattern.matcher(data);if(!match.find()) {if (Config.LOGD) Log.d(TAG, "Could not find BSSID in CONNECTEDevent string");}else {BSSID = match.group(1);try {networkId = Integer.parseInt(match.group(2));} catch (NumberFormatException e) {networkId = -1;}}}mWifiStateTracker.notifyStateChange(newState,BSSID, networkId);}void notifyStateChange(DetailedState newState, StringBSSID, int networkId) {Messagemsg = Message.obtain(this, EVENT_NETWORK_STATE_CHANGED,newNetworkStateChangeResult(newState, BSSID, networkId));msg.sendToTarget();}
DhcpThread获取EVENT_DHCP_START消息事件后,调用handleMessage()函数,启动DHCP获取IP地址的服务。
frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
public void handleMessage(Message msg) {intevent;switch (msg.what) {case EVENT_DHCP_START:……Log.d(TAG, "DhcpHandler: DHCP requeststarted");//启动一个DHCPclient的精灵进程,为mInterfaceName请求分配一个IP地//址if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {event= EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;if(LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");} else {event= EVENT_INTERFACE_CONFIGURATION_FAILED;Log.i(TAG,"DhcpHandler: DHCP request failed: " +NetworkUtils.getDhcpError());}……}
}
这里调用了一个NetworkUtils.runDhcp()函数,NetworkUtils类是一个网络服务的辅助类,它主要定义了一些本地接口,这些接口会通过他们的JNI层android_net_NetUtils.cpp文件和DHCP client通信,并获取IP地址。
至此,IP地址获取完毕,Wifi启动流程结束。

待续
(b)    Wifi模块相关文件的解析

(c)    Wpa_supplicant解析

												

android wifi模块分析相关推荐

  1. Android GNSS 模块分析(四)HAL 层

    紧接着上一篇(Android GNSS 模块分析(三)JNI 层),继续来分析下 Android GNSS HAL 层的功能,本篇准备先介绍下 HIDL 层的封装.至于后面的 HAL 层的功能,由于使 ...

  2. Android WIFI框架分析(1)

    趁做Android WIFI驱动移植,对Android WIFI框架做了深刻的分析,并做此文档共同学习. 对上层WIFI的应用,基本流程为:(1)WIFI初始化  (2)Wifi启动      (3) ...

  3. Android GNSS 模块分析(五)NMEA 协议

    紧接着上一篇<Android GNSS 模块分析(四)HAL 层>,本篇简述下导航硬件设备与卫星导航系统之间的通信协议. NMEA 协议 简介: NMEA(National Marine ...

  4. Android Wifi实现分析

    其实现在已经到了android-9了.但是这篇文档写的是android-8而且android-9的变化不是非常大,所以也懒得修改. 一.模块功能分解 老架构,网上找的.8.0以后不一样了. 1. wi ...

  5. 乐鑫wifi模块二次开发_米家部分智能硬件拆解,ZigBee/WIFI模块分析及二次开发

    点击"蓝字"关注我们 最近小编都在培训,几天没有更新,大家有没有想死小编学习啊~这周天气骤冷,秋裤可以穿起来啦~ 正文开始 ▲左到右依次是:门磁传感器,温湿度传感器,无线开关,人体 ...

  6. android wifi的进程,Android wifi简要分析

    这里列了很多,但是大致可以分为四个主要的类ScanResult wifiConfiguration WifiInfo WifiManager (1)ScanResult,主要是通过wifi 硬件的扫描 ...

  7. android camera fragment,Android Camera 模块分析(三)

    第三部分 Camera的主要实现分析 3.1 JAVA程序部分 在packages/apps/Camera/src/com/android/camera/ 目录的Camera.java文件中,包含了对 ...

  8. Android wifi模块

    工具api 1.开发细节 1 获取WifiManager入口类实例: wifiManager = (WifiManager) context.getSystemService(Context.WIFI ...

  9. Android wifi探究二:Wifi framework层源码分析

    上一篇博客初步认识了wpa_supplicant的作用和使用方法,并且尝试着梳理了wifi的大框架,不过,java层的框架我们忽略了,没有分析,也就是说上一篇博客简单的指出了wifi代码的大框架,那么 ...

最新文章

  1. Spring Boot 操作 Redis 的各种实现
  2. 校准曲线(calibration curve)是什么?如何绘制校准曲线(calibration curve)?如何通过过校准曲线进行分析?什么是高估?什么是低估?
  3. python第三方包安装方法(两种方法)
  4. python not函数_python 函数
  5. Vmware下设置Ubuntu桥接上网
  6. python语言入门u-[学习总结] python语言学习总结 (一)
  7. scala -cp file.jar filename的案例
  8. [C++调试笔记]执行声明的读写文件操作
  9. MySQL 处理海量数据时的一些优化查询速度方法
  10. P1803 凌乱的yyy / 线段覆盖
  11. Retroifit原理
  12. 操作系统——进程的状态及转换
  13. 各种数字字体样式_来自中世纪建筑 文化的字体——————哥特式
  14. 3.2 softmax多分类、tensorflow2实现——python实战
  15. 第一篇:了解和使用MVPArms项目
  16. 文本编辑器vscode编译运行c++文件(.cpp)
  17. SPSS入门教程——如何分析两个变量之间的关联度?
  18. python用for循环求和1到100_python使用for循环计算0-100的整数的和方法
  19. java后端实习第一个月总结
  20. python批量裁剪图片_python批量剪切图片实现代码

热门文章

  1. 大牛干货:一名合格的 C/C++ 开发者的标志
  2. 测试工程师,水深火热的职场,我拒绝被动等待成长用这三招直接上了高速......
  3. 【读书笔记】《认知觉醒》- 周岭
  4. TSM视频测试——中间篇
  5. 乡村认可的水泵推荐:【博山潜水泵】
  6. 【Linux从0到1】第十一篇:多线程
  7. Vue脚手架安装及项目搭建(mac版)
  8. TQ2440开发板学习纪实(9)--- 利用Undefined异常模拟BLX指令
  9. spellman电源维修PCM70N120高压发生器维修
  10. (附源码)计算机毕业设计SSM大学生创新创业项目活动管理平台