分析:Android_Wifi_HAL层

 

    本文主要是研究分析Android平台Wifi框架及HAL层需要做的相关开发工作,目前只做了wifi扫描、关联流程的基本分析,没有包括p2pHostAP相关部分。

2      基础

2.1      HAL简介

HAL Hardware Abstraction Layer的首字母缩写,意思是硬件抽象层。

1.     Windows HAL:位于操作系统的最底层,直接操作物理硬件,隔离与硬件相关的信息,为上层的操作系统和设备驱动程序提供一个统一的接口,起到对硬件的抽象作用。

 

2.     标准Linux HAL:位于操作系统和驱动程序之上,是一个运行在用户空间的服务程序,提供对所有设备和设备属性的管理功能,并与用户层应用程序进行交互。 Linux HAL框架如下:

Linux HAL主要基于udevD-BUS实现,通过sysfsuevent /etc/hal/fdi 等获取管理硬件信息。

Linux HAL的描述参见: http://www.freedesktop.org/wiki/Software/hal

3.     Android中的HAL

Android HALHardware Abstract Layer硬件抽象层)是Google因应厂商「希望不公开源码」的要求下,所推出的观念。Android HAL是由众多用户空间的动态链接模块库组成。Android HAL框架如下:

这是 Patrick Brady (Google) 2008 Google I/O 所发表的演讲「Anatomy & Physiology of an Android」中所提出的 Android HAL 架构图。Android Framwork通过HAL层来对Linux Kernel Drivers进行访问,HAL层的实现可以作为动态库或模块加载,即实现了对硬件抽象访问功能,又可达到隐藏实现代码目的。

2.2      Android HAL简介

1.     Android HAL的过去与现在

libhardware_legacy/ - 过去的实现、采取链接库模块的观念进行
libhardware/ -
新版的实现、调整为HAL stub的观念
ril/ - Radio Interface Layer

2.     旧版实现-HAL_legacy动态链接模块库 (libhardware_legacy)

Android用户应用程序或框架层代码由Java实现,Java运行在Dalvik虚拟机中,没有办法直接访问底层硬件,只能通过JNI调用来调用so本地库代码实现,在so本地库代码里运行对底层硬件操作代码,如下图所示

应用层或框架层Java代码,通过JNI调用libandroid_runtime代码来调用libhardware_legacy.so库代码,在so库代码中调用底层驱动,实现上层应用的提出的硬件操作请求。调用流程示例如下:

3.     新版实现- Hardware Module Stub  (libhardware)

新的架构使用的是module stub方式。Stub是存根或桩的意思,就是指一个硬件模块对象的代表的意思。由上面的架构可知,上层应用层或框架层代码加载runtime so库代码,这些runtime so库代码我们称之为module,在HAL层注册了每个硬件对象的存根stub,当上层需要访问硬件的时候,就从当前注册的硬件对象stub里查找,找到之后stub会向上层module提供该硬件对象的operations interface(操作接口),该操作接口就保存在了module中,上层应用或框架再通过这个module操作接口来访问硬件。

以Led为例的调用流程:

4.     HAL_legacy HAL Stub的对比

HAL_legacy:旧版的HAL,是一个采用共享库形式的模块,libhardware_legacy.so

由于采用直接函数调用形式调用,上层直接将so库映射进进程空间,因此可被多个进程使用,但会被mapping多个进程空间中,造成内存空间浪费,存在设备可能会被多次打开的问题,同时需要考虑代码能否安全重入问题

HAL Stub:新版的HAL采用HAL moduleHAL stub结合形式,需要加载的是module runtime

运行时上层只加载module库,通过HAL module提供的统一接口获取并操作HAL stub,底层Stub扮演了“接口提供者”的角色,当Stub第一次被使用时加载到内存,后续再使用时仅返回硬件对象操作接口,不会存在设备多次打开问题,并且由于Stub so文件只会被mapping到一个进程,多进程访问时返回的只是函数指针,也不存在重复mapping和重入问题。

2.3      Android Wifi分析

Android Wifi 框架:

 

(插图1)

 

 

 

1.     Wifi启动流程

开关流程:WifiSetting创建WifiEnabler; WifiEnabler响应开关按钮的onCheckedChanged()方法

onCheckedChanged( )方法里调用WifiManager.setWifiEnabled()

 WifiManager调用WifiSevice.setWifiEnabled()WifiService调用     WifiStateMachine.setWifiEnabled() WifiStateMachine向自己发消息:

 

(插图2)

 

2.     WifiStateMachine机制

Wifi状态机机制,共27个状态,采用栈的形式,子状态在栈顶,父状态依次入栈;消息自顶向下依次处理,每一个消息处理完成后会反转所有延时消息的顺序。

初始化为InitialState, 启动即判断驱动是否加载,根据结果进行状态跳转

如果驱动已加载则跳转到 DriverLoadedState,否则跳转到 DriverUnloadedState

以下仅分析开启过程正确结果处理流程,下列状态图约定:

标记为颜色绿色模块为调用本地库方法,标记为红色部分为下发WIFI命令

标记为MSG_xxx发送消息,  标记为虚线状态机状态跳转

最左侧为状态机栈,  中间为消息队列,右侧为处理函数及消息传递

 

(插图3)

 

(接上图)

 

(插图4)

以上图示为启动与扫描流程。

以下为关联流程:

 

(插图5)

 

3.     Android Wifi HAL层分析

Wifi HAL层采用的是libhardware_legacy的实现,代码主要在 hardware/libhardware_legacy/wifi/wifi.c; 提供的主要功能接口:

       插入驱动                                      wifi_load_driver

       移除驱动                                        wifi_unload_driver

启动wpa_supplicant服务             wifi_start_supplicant

                                                        wifi_start_p2psupplicant

       停止wpa_supplicant服务             wifi_stop_supplicant

       连接wpa_supplicant                      wifi_connect_to_supplicant

       传送wifi命令                               wifi_command

       读取消息                                        wifi_wait_for_event

       读取固件路径                                wifi_get_fw_path

       修改固件路径                                wifi_change_fw_path

 

Android Wifi上层Java代码通过JNI调用将上层wifi命令传递到HAL层处理。

所有的native方法都定义在Android源码WifiNative.java:

android/frameworks/base/wifi/java/android/net/wifi/WifiNative.java;

这些native方法的实现在android_net_wifi_Wifi.cpp:

android/frameworks/base/core/jni/android_net_wifi_Wifi.cpp

 

1.     DRIVER CMD, 与驱动相关命令

由上层下发往wifi驱动的私有命令 “DRIVER ”开头,

在此涉及有16个函数,24个命令:

setCountryCodeCommand           "DRIVER COUNTRY"

doSetScanMode                          "DRIVER SCAN-ACTIVE" /

                                                    "DRIVER SCAN-PASSIVE"

startDriverCommand                   "DRIVER START"

stopDriverCommand                    "DRIVER STOP"

startMultiV4Filtering                   "DRIVER RXFILTER-STOP" /

                                                  "DRIVER RXFILTER-REMOVE 2" /

                                                  "DRIVER RXFILTER-START"

stopMultiV4Filtering                   "DRIVER RXFILTER-ADD 2" /

                                                  "DRIVER RXFILTER-START"

startMultiV6Filtering                   "DRIVER RXFILTER-STOP" /

                                                  "DRIVER RXFILTER-REMOVE 3" /

                                                  "DRIVER RXFILTER-START"

stopMultiV6Filtering                   "DRIVER RXFILTER-ADD 3" /

                                                  "DRIVER RXFILTER-START"

getMacAddressCommand                    "DRIVER MACADDR"

setPowerModeCommand                     "DRIVER POWERMODE %d"

getPowerModeCommand                    "DRIVER GETPOWER"

setBandCommand                               "DRIVER SETBAND"

getBandCommand                                     "DRIVER GETBAND"

setBluetoothCoexistenceModeCommand             "DRIVER BTCOEXMODE"

setBluetoothCoexistenceScanModeCommand       "DRIVER BTCOEXSCAN-START" /

                                                                             "DRIVER BTCOEXSCAN-STOP"

setSuspendOptimizationsCommand                    "DRIVER SETSUSPENDOPT %d"

 

2.     Wifi Command通过socket发给wpa_supplicant, wpa接收。

wpa_supplicant文件 android/external/wpa_supplicant_8_bcm/wpa_supplicant/ctrl_iface.c:

函数wpa_supplicant_ctrl_iface_process()中处理:

    if (os_strncmp(buf, “DRIVER ”, 7) == 0)

           reply_len= wpa_supplicant_driver_cmd(wpa_s, buf+7, reply, reply_size);

 

3.     wpa_supplicant_driver_cmd函数在 wpa_supplicant/driver_i.h 中定义:

if (!wpa_s->driver->driver_cmd)

return -1;

return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len)

4.     driver_cmd定义在 /work/android/external/wpa_supplicant_8_bcm/src/drivers/driver_nl80211.c

6846:

#ifdef ANDROID

        .driver_cmd = wpa_driver_nl80211_driver_cmd,

#endi

5.     wpa_driver_nl80211_driver_cmd的实现在文件:

android/hardware/broadcom/wlan/bcmdhd/wpa_supplicant_8_lib/driver_cmd_nl80211.c

#ifdef ANDROID

int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len);

#endif

2.4      参考方案

从以上分析得知,支持android需要实现wpa_driver_nl80211_driver_cmd() 函数内容。

参考方案的实现:

即定义 BOARD_WPA_SUPPLICANT_PRIVATE_LIB 并实现它。

友商参考:

BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd

BOARD_HOSTAPD_PRIVATE_LIB                 := lib_driver_cmd_bcmdhd

lib_driver_cmd_bcmdhd hardware/Broadcom/wlan/bcmdhd/wpa_supplicant_8_lib/实现。

 

2.5      具体实现

1.     Android配置修改

修改android/device/hisi/k3v2oem1/BoardConfig.mk

(待改进)

 

2.     wpa_supplicant配置

从上面的配置,我们可以看出,wpa_supplicant采用的是 VER_0_8_X_HISI版本

把我们要用的wpa_supplicant文件夹重命名为hisi_wpa_supplicant并拷贝到external/

修改external/hisi_wpa_supplicant/Android.mk :

## ligang add for hi1101

ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X_HISI)

    include $(call all-subdir-makefiles)

endif

 

wpa_supplicant的编译路径在:

external/hisi_wpa_supplicant/wpa_supplicant

编辑其路径下的Android.mk:

ifdef CONFIG_DRIVER_NL80211

#L_CFLAGS += -DANDROID_BRCM_P2P_PATCH

endif

3.     开发wpa_supplicant_private_lib

hardware下面建路径 hisi/wpa_supplicant_8_lib

并在其路径下实现wpa_supplicant_private_lib内容,即函数wpa_driver_nl80211_driver_cmd.

这个私有库是作为静态库编译并链接到wpa_supplicant里面的

注:也可以把相关文件直接放在wpa_supplicant/src/drivers目录下并修改相关配置。

 

4.     配置config

hardware/hisi下面建文件夹config

并把wpa_supplicant的配置文件加入编译

 

注:配置文件也可以直接在wpa_supplicant的编译配置里添加。

5.     驱动修改

修改驱动以支持ioctl

 

6.     测试

 

7.     后续改进

 

你可能感兴趣的:(分析:Android_Wifi_HAL层)