wifi的层次结构
wifi分为以下几个层次:
- wifi setting,UI界面
- wifi framework
- wifi 硬件抽象层
- wifi 服务层
- wifi驱动层
wifi setting
wifi的ui界面主要在如下的目录中:packages\apps\Settings\src\com\android\settings\wifi.
- WifiSettings.java负责显示wifi的设置界面。
- WifiEnabler.java主要是wifi的开关逻辑
- WifiDialog.java负责wifi的对话框显示
- AdvancedSettings.java负责wifi的高级选项的显示
- AccessPoint.java表示一个ap所有属性的一个类
- WifiInfo.java主要是wifi的一些配置信息,列如鉴权方式,密码,ssid等
wifi界面的编译输出是在settings.apk中。为什么要说每层的编译输出结果呢,因为在调试中,你可能只是修改了某一层的某几个文件而已,这时候,你没必要重新编译整个文件系统,而只要编译这一层对应的输出,然后通过adb或其他的途径替换原有的包,再重起目标板,就可以生效了。
wifi framework
wifi的framework主要有如下几个类:
- framework/base/wifi/java/android/net/wifi/wifiManager.java
- framework/base/services/java/com/android/wifiService.java
- framework/base/wifi/java/android/net/wifi/wifiMonitor.java
- framework/base/core/jni/android_net_wifi_wifi.cpp
他们的编译输出主要有两个类:一个framework.jar,另一个是services.jar,由于这一层的修改要编译整个framework 或services,所以编译时间长,调试花费时间长。但理论上,可以只编译修改的类,然后替换framework.jar或services.jar对应的类即可。该过程可以通过java的perl脚本来实现,可以大大节省编译的时间,加快调试的进度,好言归正传!
wifiManager.java是通过ibinder调用到wifiservice.java的,wifiManager.java只是封装了一些供sdk开发用的api接口,如果要了解当前sdk关于wifi相关的api,可以查看android文件系统的current.xml文件,wifiManager.java现实的主要功能都是在wifiservice.java中实现的,所以wifisercie.java是我们研究wifi的主要对象。
wifiservice.java主要是执行一些wifi的命令,如扫描,连接ap,断开ap等,更详细的就没必要说了,看代码。但需要知道,这个类主要就是用来执行wifi的命令的,wifi是有两条路的,一条是执行命令的路径,一条是接口事件的路径。而wifiservice.java正是用来执行命令的。
而wifiMonitor.java就是用来接收服务层上来的事件的,例如:断开,连接,有扫描结果等事件,也就是刚说的wifi的另一条路径。
而android_net_wifi_wifi.cpp就是典型jni接口了,通过它来直接调用到wifi的硬件抽象层。
wifi 硬件抽象层
wifi的硬件抽象层就是:hardware/libharedware_legacy/wifi/wifi.c,该层居于wifi framework与wifi wpa_supplicant服务层之间,起着承上启下的作用,具体是:android_net_wifi_wifi.cpp中的大部分接口都是直接有wifi.c文件来实现,该文件通过socket接口来跟wifi服务层来通讯。
wifi 服务层
wifi的服务层就是wpa_supplicant层,该层是wifi framework层的基石,该层与上层的wifi.c通过socket通讯方式来实现控制接口,同样也是通过socket通讯方式实现了事件接口,控制接口对应用于wifiservice.java的命令的发送;而事件接口对应用wifimonitor.java的事件的接收。从而实现了命令和事件两条通路。
该层的代码路径是:external/wpa_supplicant/目录下。
wpa_supplicant的功能很强大,在目前的android机器里,wifi除了传输应用数据不会经过wpa_supplicant这一层以外,其他上层所有相关的功能都会间接的调用的wpa_supplicant这一层。譬如:点击扫描按钮,连接ap,断开ap,信号强度的动态改变,获取扫描结果,鉴权,等等都是要通过wpa_supplicant来执行实际的功能。
而这一层跟wifi的驱动就典型的socket系统调用了,大家都知道使用socket,得指定所使用的协议族,在这里,PF_INET协议就是我们通用的tcp/ip协议;而PF_NETLINK协议族是用于wpa_supplicant获取内核上来的事件的;而PF_PACKET协议族是说用于接收基于链路层上的裸数据的,该协议主要用来做鉴权的,诸如wpa,wpa2,wapi等。
wifi驱动层
该层是在内核目录下,有两种存在形式,一个是模块驱动方式,此时代码就可能不在内核里,一种是内核内建(buit-in)方式,就是包含在内核里,linux内核已经支持了很多的wifi网卡的驱动。通常在目录内核根目录:drivers\net\wireless下面。
wifi驱动从某种意义上将可以分为两种:一种是硬件mac,就是mac协议由硬件实现,当然省时又省力了。另一种是软mac,就是由软件来实现mac,软件复杂些,但可以节省硬件成本。软mac在linux下的目录如下:net/mac80211。
wifi从硬件接口上将,分为sdio接口,usb接口,pcmcia接口。目前嵌入式上主流是sdio接口和usb接口。分别需要硬件资源有sdio控制器和usb主控制器及相应的驱动的支持。
wifi驱动架构遵循一般的网络设备驱动模型的架构,当然又不同于一般的有线网络驱动模型。具体的鉴于篇幅在这里就不详细讨论了,因为这一篇是讨论架构的,不拘泥于细节的。
最后:讲了这么多层次结构,怎么样把他们串起来呢?这个要留给读者了,但我可以给你一个不坏的建议(如果你不能提供更好的建议的话):你可以在手机上点击扫描操作,看扫描命令时怎么样发送下去,直止驱动里是怎么驱动的,而后wifi网卡接收到驱动里的扫描命令后,开始努力的扫描,扫描完后,如果有扫描结果,会通过事件又是怎么样将扫描结果上传给wifi上层并显示出来的。