本文將詳細介紹基于MTK平臺,適配高通(Qualcomm)QCA6696芯片的Android WLAN HAL層的移植過程,包括HIDL接口定義、Wi-Fi驅動移植以及wpa_supplicant適配過程,涵蓋STA與AP模式的常見問題與解決方法。
1. HIDL接口簡介
HIDL(HAL Interface Definition Language)是一種用于定義Android HAL層與Framework之間接口的描述語言(IDL),其核心目的是隔離Framework與廠商提供的HAL實現,使得Framework更新時,無需重新編譯廠商的HAL組件。廠商可獨立編譯并在Vendor分區中單獨更新。
HIDL架構
HIDL架構由接口定義、服務端(Server)和客戶端(Client)三部分構成。
- 接口定義(Interface):.hal文件,定義接口及其方法。
- 服務端(Server):實現HIDL接口,接收客戶端調用并返回數據。
- 客戶端(Client):調用服務端提供的接口。
Android 8.0以前,HAL以.so庫形式與Framework同進程運行;8.0之后則分屬不同進程,通過HIDL進行通信。

2. HIDL的關鍵文件
HIDL相關的重要文件包括:
- .hal接口定義文件,如IWifi.hal等以.hal為結尾的文件都是自己創建添加的。這里定義一些未實現的接口。
- 根據.hal生成的.cpp和.h文件,每對這個文件都是根據前面的.hal生成的,這對文件是實現接口的關鍵文件。
- 相關服務啟動文件,如android.hardware.wifi@1.0-service.rc、service.cpp。
- 構建文件,如Android.mk、Android.bp是用Andriod提供的工具生成
以setcountrycode為例:frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiNative.java
frameworks\opt\net\wifi\service\java\com\android\server\wifi\SupplicantStaIfaceHal.java
hardware\interfaces\wifi\supplicant\1.0\ISupplicantStaIface.hal
external\wpa_supplicant_8\wpa_supplicant\hidl\1.1\sta_iface.cpp
3. 移植(STA部分)
Wi-Fi驅動中的wpa_supplicant不是使用的HIDL,換句話說不是為了Andriod設計的,所以我們要使用MTK平臺原生的wpa_supplicant。

boardconfig.mk的修改,這里面用到的宏盡量保持和在高通平臺用的一致。


準備適配高通的wpa_supplciant時出現問題,關鍵在于高通的這個wpa_supplicant用的是1.2的,要改成和原來適配的1.1,像下面的報錯就是wpa_supplicant中客戶端調用的hidl接口沒有完全滿足。

這個時候就去external\wpa_supplicant_8\wpa_supplicant\hidl\1.1下面去把這些聲明加上嗎,這是一個比較耗時的操作。

遇到下面這個問題時,換個ctrl_interface
09-01 06:26:22.755 3699 3699 E wpa_supplicant: mkdir[ctrl_interface=/var/run/wpa_supplicant]: No such file or directory09-01 06:26:22.755 3699 3699 E wpa_supplicant: Failed to initialize control interface '/var/run/wpa_supplicant'.
如下:
ctrl_interface=/data/vendor/wifi/wpa/sockets#ctrl_interface=/var/run/wpa_supplicant

因為我們執行wpa_cli默認的接口是/var/run/wpa_supplicant,當我們執行wpa_cli時就會去這個接口里找socket,所以此時應該指定接口:
wpa_cli -i wlan0 -p /data/vendor/wifi/wpa/sockets # 這個ctrl_interface只是創建了一個sockets給用戶側交互而已。
把Wi-Fi驅動名字換成wlan.ko,否則會報類似下面的錯誤:

在我第一天把STA模式導通后,后面導通完AP模式,再來看STA模式時,發現總是報下面的log,找不到原因。

然后就代碼跟進去一行一行的看,才發現是以下導致的。
我首先發現以下不對,我是從界面上點擊Wi-Fi按鈕,log中也能看到WLAN0口起來了
09-16 07:43:01.267 2410 2410 E wificond: :p2p0:wlan009-16 07:43:01.267 2410 2410 E wificond: :wlan0:wlan0
為什么下面的代碼走的是IfaceType::P2P的分支??

進一步追代碼可知,在supplicant.cpp中通過調用wpa_supplicant_get_iface來獲取global 接口,默認接口被p2p填充了,而在p2p_supplciant.c中能看到若p2p_disabled參數沒有被定義,則p2p會把整個init流程走下來。也就是出問題的點。


而最根本的原因是wpa_supplicant_overlay.conf不知道什么原因沒有了,所以得把這個文件加在下面默認的目錄下/vendor/etc/wifi/,然后在wpa_supplicant_overlay.conf中會默認定義p2p_disabled=1。
Supplicant.cpp:constexpr char kStaIfaceConfOverlayPath[] ="/vendor/etc/wifi/wpa_supplicant_overlay.conf";
下面是正常Log(左側)和異常Log(右側)的對比。

下面是正常Log:
09-17 05:20:22.112 2912 2912 E wpa_supplicant: Initializing interface 'wlan0' conf '/data/vendor/wifi/wpa/wpa_supplicant.conf' driver 'nl80211' ctrl_interface 'N/A' bridge 'N/A'09-17 05:20:22.112 2912 2912 E wpa_supplicant: Configuration file '/data/vendor/wifi/wpa/wpa_supplicant.conf' -> '/data/vendor/wifi/wpa/wpa_supplicant.conf'09-17 05:20:22.112 2912 2912 D wpa_supplicant: Reading configuration file '/data/vendor/wifi/wpa/wpa_supplicant.conf'09-17 05:20:22.112 2912 2912 D wpa_supplicant: update_config=109-17 05:20:22.112 2912 2912 D wpa_supplicant: eapol_version=109-17 05:20:22.113 2912 2912 D wpa_supplicant: ap_scan=109-17 05:20:22.113 2912 2912 D wpa_supplicant: fast_reauth=109-17 05:20:22.113 2912 2912 D wpa_supplicant: pmf=109-17 05:20:22.113 2912 2912 D wpa_supplicant: p2p_add_cli_chan=109-17 05:20:22.113 2912 2912 D wpa_supplicant: Reading configuration file '/vendor/etc/wifi/wpa_supplicant_overlay.conf'09-17 05:20:22.113 2912 2912 D wpa_supplicant: disable_scan_offload=109-17 05:20:22.113 2912 2912 D wpa_supplicant: p2p_disabled=1
4. 移植(AP部分)
1、AP部分:出現下面的log時,把hostapd.conf中的下面參數注釋掉
#ctrl_interface_group=radio09-10 08:45:53.858 3720 3720 D hostapd : Using existing control interface directory.09-10 08:45:53.858 3720 3720 E hostapd : billy ctrl_interface_gid_set:1,ctrl_interface:/data/vendor/wifi/wpa/sockets,ctrl_interface_gid:1001,ctrl_iface_group:009-10 08:45:53.858 3720 3720 E hostapd : billy1 lchown[ctrl_interface]: Operation not permitted09-10 08:45:53.858 3720 3720 E hostapd : Failed to setup control interface for wlan0
2、出現下面的權限問題時chmod 777 /sys/module/wlan/parameters/fwpath

3、解決完了會遇到下面的問題。
09-10 10:52:23.461 4043 4043 E android.hardware.wifi@1.0-service: Unknown iface name: ap0

我在hardware/interface下面發現createApIfaceInternal里面獲取interface時直接寫死成了ap0,不知道是不是MTK的操作。Ap0我們是沒有這樣的接口的,把它釋放后,上面的錯誤就OK了。

下面是起AP時起的wlan0口。
09-15 00:43:38.992 2579 2677 I WifiNative: Interface state changed on Iface:{Name=wlan0,Id=16,Type=AP}, isUp=true09-15 00:43:38.992 2579 2677 I WifiNative: Successfully setup Iface:{Name=wlan0,Id=16,Type=AP}
5. 總結
通過上述方法和注意點,能順利完成MTK平臺對QCA6696 WLAN HAL層的移植。整體改下來,主要是改的wpa_supplciant下面的hidl和.c部分,比較少改動hardware/interface/下面,沒有改動framework部分。
也就是說主要改的是HIDL 的server端,即接收hidl調用并返回數據的一方,client端怎么調用那是固定好的,比如在該獲取interface的時候我們不管它怎么調,我能保證我返回的interface可用就行。