1. Wifi扫盲... 4
2. Android Wifi框架的结构图... 5
3. wpa_supplient 5
4. Netd. 7
5. FrameWork层架构... 7
6. 情景分析... 8
6.1. 情景1. 8
6.2. 情景2. 11
6.3. 情景3. 11
7. Ad hoc的支持... 15
8. wifi direct 16
9. Soft ap支持... 17
10. Wifi Tethering支持... 20
11. Usb Tethering支持... 21
12. Reverse usb Tethering. 21
13. 需要改动的地方... 22
14. 测试... 22
1. Wifi扫盲
Access point: 也叫hotspot(热点), 家里的无线路由就是ap。
SoftAp:软ap, 用无线网卡模拟ap的功能。
Wifi网络有两种模式:
请参考http://en.kioskea.net/contents/wifi/wifimodes.php3
我们既可以通过Ad hoc也可以通过SoftAp方式来实现共享网络(例如手机可以通过笔记本访问internet), 但是原理不同。
这里只是简单的概括, 详细的解释请google或百度。
2. Android Wifi框架的结构图
上图只是wifi工作于station模式时的图, 当工作于soft ap模式时最基本的不同是不通过wpa_supplicant而是Framework层直接通过netd daemon来控制驱动。
3. wpa_supplient
虽然本文不关心JNI层以下的部分, 但wpa_supplient是什么需要解释一下。 WPA是WiFi Protected Access的缩写, wpa_supplicant是“WiFi网络安全存取认证”的意思。Android是用的wpa_supplicant的修改版本。
在Android wifi框架里, wpa_supplcant起着承上启下的作用。 它向上提供netlink socket接口, 向下依赖wifi驱动的wireless extention标准接口。 也就是说驱动必须支持wireless extention才可以。wireless extention其实是一个将要过时的标准, Android也将向nl80211标准过度, 采用未修改的wpa_supplicant。
请参见http://wireless.kernel.org/en/developers/Documentation/Android。
本节以下部分摘自《Android平台上无线网卡自动扫描并关联AP的实现》:http://hi.baidu.com/xyp86/blog/item/d371a1d78d4162d7a144dfd3.html。
Android平台使用的WiFi控制框架是基于大名鼎鼎的wpa_supplicant,它是一个安全中间件,为各种无线网卡提供统一的安全机制,如下图所示:
客户端程序,包括wpa_cli命令行或java图形界面程序,通过unix本地socket与
wpa_supplicant daemon服务通信,发送命令并接收结果;wpa_supplicant daemon服务,对应上述中间部分,功能是“上传下达”。所有客户端通过它控制硬件网卡,通过发送字符串命令控制是否扫描AP,提取扫描结果和是否关联AP等操作,同时将驱动的执行状态发送给用户。该服务是设计支持多种无线网卡芯片,因此各个厂商共同提供了一个通用接口给wpa_supplicant调用
4. Netd
Netd是android的一个守护进程, 是专门为Android开发的。 它功能很广, 包括设置nat, usb tethering, wifi tethering, soft ap设置, 还有网络接口add, remove, change事件的通知。 在FrameWork有NetworkManagementService负责和netd通信,framework代码可以通过 NetworkManagementService利用netd的全部功能。Netd的代码位于“android sources”/system/netd。
5. FrameWork层架构
6. 情景分析
6.1. 情景1
当前系统正连接了以太网, Wifi是未使能的, 有无密码的Wifi信号存在, Wifi的优先级高于以太网。 此时在Settings使能Wifi, 系统就会连接到Wifi网络, 那么整个过程是怎样的呢?
下面是整个过程的UML序列图。
当在settings使能Wifi后, 首先会调用WifiService.setApEnabled(false), 也就是禁止Wifi模块的作为Ap(Access Point, 即一个接入点)的功能。需要了解的是, 现在的硬件Wifi模块即支持去连接附近的Ap, 也可以作为Ap供其它设备接入。那么给其它设备接入有什么用处呢? 那就是tethering, 即网络共享。 假设你的设备当前可以通过以太网访问因特网, 当在Wifi上使能Ap功能时, 其它连入的设备就可以通过这台设备访问因特网。 当然在同一时刻, 只能有一种身份。
接着会调用WifiService.setWifiEnabled(true), 去加载wifi适配层, 启动supplient守护进程, 启动MonitorThread开始监听supplient的事件。
首先 MonitorThread会收到DRIVER_STATE事件, 意味着硬件启动成功。 接着会调用到WifiNative.scanCommand()向supplient发送搜索Ap的命令。然后MonitorThread又进入等待事件的状态。
当supplient搜索Ap结束时, MonitorThread会收到SCAN_RESULTS事件。 接下来会调用WifiNative. setScanResultHandlingCommand(NormalMode)来让supplient自行决定去连接到哪个Ap, supplient会挑选信号最强并且没有密码的Ap进行连接。同时WifiSettings会收到WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播,调用mWifiManager.getScanResults()得到扫描到得ap列表。 ScanResult里包含如下信息:
public String SSID;
public String BSSID;
public String capabilities;
public int level;
public int frequency; |
下面是几个ScanResult的例子: SSID=”Exotica” FEATURES=”[WPA2-PSK-CCMP]” FREQ=2422 LEVEL=-40 BS=”01:02:03:04:05:06”
SSID=”Exotica” FEATURES=”[WEP]” FREQ=2432 LEVEL=-50 BS=”02:03:04:05:06:07” |
当supplient连接到一个Ap时, MonitorThread会收到CONNECTED事件。 接下来就会尝试配置IP地址, 如果IP地址配置成功就会发送EVENT_STATE_CHANGED给ConnectivityService,ConnectivityService就会根据网络优先级决定关掉以太网而通过Wifi联网的决定。这里要区分网络接口的disconnect和disable的不同之处, disconnected的接口依然可能enable, disable是指硬件上的。 在pc上当切换到其他网络只是disconnected以前的网络, 而Android为了省电, 是disable以前网络的。
6.2. 情景2
系统启动时, Wifi和Ethernet都处于使能状态, 并且附近有没有密码的Wifi信号, Ethernet也是通的。系统启动后就会自动连接到Wifi网络, 那么系统启动时如何决定连接到哪个网络呢?
在上一篇《Android的网络支持和管理(一)---以太网》中, 我们分析了从网线插上到以太网通畅的全过程。 这过程中驱动层一共向上发出了两个信号, 第一个代表硬件连接上了, 第二个代表网络连接上了(即IP地址配置成功)。
刚才我们又分析了当使能Wifi到Wifi通畅的全过程。 这过程中驱动层一共向上发了三个信号, 第一个代表硬件使能成功,第二个代表搜索Ap完毕, 第三个代表网络连接上了(即IP地址配置成功)。
在IP地址配置成功以前, 以太网和Wifi都是默默做着自己的工作, 丝毫没有参与网络管理。 当即IP地址配置成功后, 能够确保各自网络通畅时, 才通知ConnectivityManager。
当启动时,如果以太网使能的话, 不管有没有网线连接都会去尝试根据保存的设置配置IP地址, 如果IP地址配置成功就会通知ConnectivityManager。同样, 如果Wifi使能的话, 就会加载Wifi驱动和启动wpa_supplient, 然后搜索AP并尝试连接, 接下来配置IP地址, 如果成果的话就会通知 ConnectivityManager。(注:WifiService.startWifi函数会在ConnectivityManager的构造函数里面调用去判断是不是要使能Wifi)无论ConnectivityManager先收到Wifi发出的信号还是以太网发出的信号, 最后的结果都是一样的, 当收到第二个信号时就会禁掉优先级小的以太网。
6.3. 情景3
系统中只有Wifi, 附近有好几个有密码的Ap, 当在Settings里使能Wifi后, 会搜索到这些Ap并显示出来。 我们选择一个Ap后会弹出WifiDialog要求输入密码, 输入密码后点确定。 下面是随后的过程。
我们在WifiDialog中配置的信息可以用WifiConfigure来表示, 它包含的信息如下:
public int networkId;
public int status;
public String SSID;
public String BSSID;
public String preSharedKey;
public String[] wepKeys;
public int wepTxKeyIndex;
public int priority;
public boolean hiddenSSID;
public BitSet allowedKeyManagement;
public BitSet allowedProtocols;
public BitSet allowedAuthAlgorithms;
public BitSet allowedPairwiseCiphers;
public BitSet allowedGroupCiphers; |
ScanResult是Ap广播的信息,而WifiConfigure是wpa_supplicant用来尝试和Ap进行连接的信息。ScanResult说“窗前明月光”, WifiConfigure只有说“疑是地上霜”才能匹配。 WifiConfigure和wpa_supplicant配置文件里保存的信息格式是对应的, 关于wpa_supplicant更详细的介绍请看源码下的readme 。 可以说wpa_supplicant实现了所有我们需要的功能, 包括ap搜索, 连接,甚至设置的保存。Settings界面通过WifiManager来和wpa_supplicant通信。