Skip to main content
 首页 » 编程设计

Android HIDL学习记录

2022年07月19日20cyq1162

一、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;

重新编译系统进行验证。

补充:

1.  getBluetoothMacAddress_cb 回调一般都是void类型的,不应该在实现时还有返回参数。


本文参考链接:https://www.cnblogs.com/hellokitty2/p/10598227.html