一、HIDL簡單介紹
HIDL是Android8.0新出的一個技能,以service和client的方式實現hal接口,目的是想使Android系統和BSP解綁,使系統升級更加方便。HIDL的使用方法一般是先提供.hal文件,然后使用hidl-gen工具生成 框架源文件和Android.bp編譯工具文件,之后填充生成的源文件和定制Android.bp編譯文件。
二、修改源HIDL文件添加hal接口
以Qucomm藍牙模塊額外提供BT MAC地址訪問接口為例進行機介紹
[ubuntu @fm]$ tree . ├── 1.0 │ ├── Android.bp │ ├── Android.mk │ ├── hidl-gen.sh │ ├── IFmHciCallbacks.hal │ ├── IFmHci.hal │ └── types.hal └── Android.bp
1.修改提供.hal文件
# cat vendor/qcom/proprietaryinterfaces/fm/1.0/IFmHci.hal package vendor.qti.hardware.fm@1.0; interface IFmHci { sendHciCommand(HciPacket command); + getBluetoothMacAddress() generates (MacRet mret); //添加這個接口,MacRet (void)類型 }; # cat vendor/qcom/proprietaryinterfaces/fm/1.0/types.hal package vendor.qti.hardware.fm@1.0; struct MacRet { //添加這個結構體 uint8_t mac0; //寫成數組測試不行,hidl不自持吧。 uint8_t mac1; uint8_t mac2; uint8_t mac3; uint8_t mac4; uint8_t mac5; int8_t ret; };
2.重新生成1.0目錄下的Android.bp和Android.mk
這兩個文件是hidl-gen根據hal文件自動生成的,用戶不要去改。因為hal文件變了,因此需要重新生成。
# rm 1.0/Android.mk # rm 1.0/Android.bp # hidl-gen -Landroidbp -r vendor.qti.hardware:vendor/qcom/proprietary/interfaces -r android.hidl:system/libhidl/transport vendor.qti.hardware.fm@1.0 # hidl-gen -Lmakefile -r vendor.qti.hardware:vendor/qcom/proprietary/interfaces -r android.hidl:system/libhidl/transport vendor.qti.hardware.fm@1.0 //一般情況下只需要重新生成Android.bp就可以了。
3.生成hal文件中新添加函數的C++代碼實現框架
可以根據hal文件生成cpp文件,然后從新生成的cpp文件中拷貝出getBluetoothMacAddress的cpp實現框架,然后將其拷貝到原cpp文件中。注意,需要在指定在一個臨時的目錄中生成C++實現框架文件,以免將已經存在原來的C++文件覆蓋掉。
# hidl-gen -o tmp_dir -Lc++-impl -r vendor.qti.hardware:vendor/qcom/proprietary/interfaces -r android.hidl:system/libhidl/transport vendor.qti.hardware.fm@1.0
此時會在tmp_dir中生成FmHci.cpp文件和FmHci.h文件,拷貝這兩個文件中getBluetoothMacAddress()到原來的C++實現文件的對應位置
# cat FmHci.h struct FmHci : public IFmHci { ... Return<void> getBluetoothMacAddress(getBluetoothMacAddress_cb _hidl_cb) override; //拷貝過來 ... }; # cat FmHci.cpp Return<void> FmHci::getBluetoothMacAddress(getBluetoothMacAddress_cb _hidl_cb) { //參數是個回調函數 bool ret; MacRet mret; //這里不需要加struct ret = BluetoothAddress::GetLocalAddress((uint8_t *)&mret); if (ret == true) { mret.ret = true; } else { memset(&mret, 0, sizeof(mret)); mret.ret = false; } _hidl_cb(mret); //給回調函數傳參,回調的函數來自client return Void(); }
4.收尾工作
(1)使用using導入使用的元素
FmHci.h中:
using android::hardware::bluetooth::V1_0::implementation::BluetoothAddress; //導入FmHci.cpp文件中使用到的BluetoothAddress::GetLocalAddress()所在的類。
(2)添加頭文件搜索路徑
在Android.mk中:
LOCAL_C_INCLUDES += vendor/qcom/proprietary/qmi-framework/inc LOCAL_C_INCLUDES += vendor/qcom/proprietary/qmi/inc LOCAL_C_INCLUDES += vendor/qcom/proprietary/bt/hci_qcomm_init
若此時能編譯成功,則Service端添加的這個hal接口就添加好了。
5.編寫測試程序進行驗證
一般測試程序放在/external/tools目錄下,也可以放在hal實現目錄下的vts目錄下
(1)編寫測試cpp文件
//[ubuntu @btaddr_test]$ cat btaddr_client.cpp #include <stdio.h> #include <android/hardware/btaddr/1.0/IBtaddr.h> #include <android/hardware/btaddr/1.0/types.h> using ::android::hardware::btaddr::V1_0::IBtaddr; using ::android::hardware::btaddr::V1_0::MacRet; using namespace std; MacRet g_mret; IBtaddr::getBluetoothMacAddress_cb get_mac_addr(android::hardware::btaddr::V1_0::MacRet mret) { g_mret = mret; return nullptr; } int main() { android::sp<IBtaddr> service = IBtaddr::getService(); if (service == nullptr){ printf("SFL: Failed to get service\n"); return -1; } service->getBluetoothMacAddress(get_mac_addr); printf("MAC=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", g_mret.mac0, g_mret.mac1, g_mret.mac2, g_mret.mac3, g_mret.mac4, g_mret.mac5); return 0; }
(2)編寫Android.bp
//[ubuntu @btaddr_test]$ cat Android.bp cc_binary { name: "btaddr_test", vendor: true, srcs: ["btaddr_client.cpp"], cflags: ["-Wall"], shared_libs: [ "liblog", "libutils", "libhidltransport", "android.hardware.btaddr@1.0", "libhidlbase", "libbase", ], }
(3)將測試程序btaddr_test安裝到文件系統
在device/qcom/common/base.mk中添加
XX_TEST_APPS += demo_client //XX_TEST_APPS環境變量里面的所有可執行程序都會被編譯進文件系統
然后就可以重新燒錄驗證了。
三、獨立實現HIDL文件
1.實現.hal文件
/media/ubuntu/work/g6pa_mount/G6PA_NEW/LINUX/android/hardware/interfaces/btaddr [hardware/interfaces/btaddr: @btaddr]$ tree . ├── 1.0 ├── IBtaddr.hal └── types.hal //# cat 1.0/IBtaddr.hal package android.hardware.btaddr@1.0; interface IBtaddr { getBluetoothMacAddress() generates (MacRet mret); }; //# cat 1.0/types.hal package android.hardware.btaddr@1.0; struct MacRet { uint8_t mac0; uint8_t mac1; uint8_t mac2; uint8_t mac3; uint8_t mac4; uint8_t mac5; int8_t ret; };
2.由hal文件生成C++實現文件
# hidl-gen -o hardware/interfaces/btaddr/1.0/default -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.btaddr@1.0 會在1.0/default下生成Btaddr.cpp 和Btaddr.h # hidl-gen -o hardware/interfaces/btaddr/1.0/default -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.btaddr@1.0 會在1.0/default下生成Android.bp # ./hardware/interfaces/update-makefiles.sh 會在btaddr下生成Android.bp 1.0下生成Android.bp和Android.mk 此時: [ubuntu @btaddr]$ tree . ├── 1.0 │ ├── Android.bp │ ├── Android.mk │ ├── default │ │ ├── Android.bp │ │ ├── Btaddr.cpp │ │ └── Btaddr.h │ ├── IBtaddr.hal │ └── types.hal └── Android.bp
3.實現生成C++文件
//[ubuntu @btaddr]$ cat 1.0/default/Btaddr.cpp #define LOG_TAG "android.hardware.btaddr@1.0-impl" #include <string.h> #include <errno.h> #include "Btaddr.h" namespace android { namespace hardware { namespace btaddr { namespace V1_0 { namespace implementation { // Methods from IBtaddr follow. Return<void> Btaddr::getBluetoothMacAddress(getBluetoothMacAddress_cb _hidl_cb) { MacRet mret; mret.ret = 0; mret.mac0 = 0x11; mret.mac1 = 0x22; mret.mac2 = 0x33; mret.mac3 = 0x44; mret.mac4 = 0x55; mret.mac5 = 0x66; _hidl_cb(mret); return Void(); } // Methods from ::android::hidl::base::V1_0::IBase follow. IBtaddr* HIDL_FETCH_IBtaddr(const char* /* name */) { return new Btaddr(); } } // namespace implementation } // namespace V1_0 } // namespace btaddr } // namespace hardware } // namespace android
//[ubuntu @btaddr]$ cat 1.0/default/Btaddr.h #ifndef ANDROID_HARDWARE_BTADDR_V1_0_BTADDR_H #define ANDROID_HARDWARE_BTADDR_V1_0_BTADDR_H #include <android/hardware/btaddr/1.0/IBtaddr.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android { namespace hardware { namespace btaddr { namespace V1_0 { namespace implementation { using ::android::hardware::hidl_array; using ::android::hardware::hidl_memory; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::sp; using ::android::hardware::btaddr::V1_0::IBtaddr; using ::android::hardware::btaddr::V1_0::MacRet; struct Btaddr : public IBtaddr { // Methods from IBtaddr follow. Return<void> getBluetoothMacAddress(getBluetoothMacAddress_cb _hidl_cb) override; // Methods from ::android::hidl::base::V1_0::IBase follow. }; // FIXME: most likely delete, this is only for passthrough implementations // extern "C" IBtaddr* HIDL_FETCH_IBtaddr(const char* name); } // namespace implementation } // namespace V1_0 } // namespace btaddr } // namespace hardware } // namespace android #endif // ANDROID_HARDWARE_BTADDR_V1_0_BTADDR_H
4.添加service.cpp和啟動此service的android.hardware.btaddr@1.0-service.rc文件
//[ubuntu @btaddr]# cat 1.0/default/service.cpp [ubuntu @btaddr]$ cat 1.0/default/service.cpp #define LOG_TAG "android.hardware.btaddr@1.0-service" #include <android-base/logging.h> #include <hidl/HidlTransportSupport.h> #include <android/hardware/btaddr/1.0/IBtaddr.h> #include <hidl/LegacySupport.h> #include "Btaddr.h" using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using android::hardware::btaddr::V1_0::implementation::Btaddr; int main() { configureRpcThreadpool(1, true); Btaddr addr; auto status = addr.registerAsService(); CHECK_EQ(status, android::OK) << "Failed to register btaddr HAL implementation"; joinRpcThreadpool(); return 1; } [ubuntu @btaddr]# cat 1.0/default/android.hardware.btaddr@1.0-service.rc service btaddr-hal-1-0 /vendor/bin/hw/android.hardware.btaddr@1.0-service class core user root group root
5.修改編譯service的Android.bp
[ubuntu @btaddr]# cat 1.0/default/Android.bp cc_binary { name: "android.hardware.btaddr@1.0-service", vendor: true, relative_install_path: "hw", init_rc: ["android.hardware.btaddr@1.0-service.rc"], srcs: [ "Btaddr.cpp", "service.cpp", ], cflags: [ "-Wall", ], shared_libs: [ "libhidlbase", "libhidltransport", "libutils", "android.hardware.btaddr@1.0", "liblog", "libutils", "libbase", ], }
在btaddr下mm,若能build過,Service端就實現好了
6.將編譯出的service可執行程序編譯進文件系統
在/device/$(Vender)/$(Product)/$(Product).mk中添加: PRODUCT_PACKAGES += android.hardware.btaddr@1.0-service
7.將這個hwservice注冊到系統(這樣getService()才能找到它) 在/device/$(Vender)/$(Product)/manifest.xml中添加:
<hal format="hidl"> <name>android.hardware.btaddr</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IBtaddr</name> <instance>default</instance> </interface> </hal>
8.添加selinux權限
在device/qcom/sepolicy/common/hwservice_contexts中添加:
android.hardware.btaddr::IBtaddr u:object_r:hal_btaddr_hwservice:s0
android.hardware.btaddr::MacRet u:object_r:hal_btaddr_hwservice:s0
在device/qcom/sepolicy/common/hwservice.te中添加:
type hal_btaddr_hwservice, hwservice_manager_type;
在device/qcom/sepolicy/msm8996/file_contexts中添加:
/(vendor|system/vendor)/bin/hw/android.hardware.btaddr@1.0-service u:object_r:hal_btaddr_default_exec:s0
添加文件:device/qcom/sepolicy/msm8996/hal_btaddr_default.te
# cat device/qcom/sepolicy/msm8996/hal_btaddr_default.te
type hal_btaddr_default, domain;
type hal_btaddr_default_exec, exec_type, vendor_file_type, file_type;
allow hal_btaddr_default sysfs:file rw_file_perms;
allow hal_btaddr_default hwservicemanager_prop:file r_file_perms;
allow hal_btaddr_default hwservicemanager:binder { transfer call };
allow hal_btaddr_default hal_btaddr_hwservice:binder call;
allow hal_btaddr_default hal_btaddr_hwservice:hwservice_manager { add find };
allow hal_btaddr_default hidl_base_hwservice:hwservice_manager add;
init_daemon_domain(hal_btaddr_default)
在/device/qcom/sepolicy/msm8996/hwservicemanager.te中添加:
allow hwservicemanager hal_btaddr_default:process getattr;
allow hwservicemanager hal_btaddr_default:binder { transfer call };
allow hwservicemanager hal_btaddr_default:file r_file_perms;
allow hwservicemanager hal_btaddr_default:dir search;
重新編譯系統進行驗證。
