一、android hidl完整樣例實現

一、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 [email protected];
interface IFmHci {
     sendHciCommand(HciPacket command);
+    getBluetoothMacAddress() generates (MacRet mret); //添加這個接口,MacRet (void)類型
};

# cat vendor/qcom/proprietaryinterfaces/fm/1.0/types.hal
package [email protected];
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 [email protected]
# hidl-gen -Lmakefile -r vendor.qti.hardware:vendor/qcom/proprietary/interfaces -r android.hidl:system/libhidl/transport [email protected]    //一般情況下只需要重新生成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 [email protected]
此時會在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",
        "[email protected]",
        "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 [email protected];

interface IBtaddr {
    getBluetoothMacAddress() generates (MacRet mret);
};


//# cat 1.0/types.hal
package [email protected];

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 [email protected]
會在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 [email protected]
會在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 "[email protected]"

#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的[email protected]文件

複製代碼

//[ubuntu @btaddr]# cat 1.0/default/service.cpp
[ubuntu @btaddr]$ cat 1.0/default/service.cpp 
#define LOG_TAG "[email protected]"

#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/[email protected] 
service btaddr-hal-1-0 /vendor/bin/hw/[email protected]
    class core
    user root
    group root

複製代碼

 

5.修改編譯service的Android.bp

複製代碼

[ubuntu @btaddr]# cat 1.0/default/Android.bp 
cc_binary {
    name: "[email protected]",
    vendor: true,
    relative_install_path: "hw",
    init_rc: ["[email protected]"],
    srcs: [
        "Btaddr.cpp",
        "service.cpp",
    ],
    cflags: [
        "-Wall",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "[email protected]",
        "liblog",
        "libutils",
        "libbase",
    ],
}

複製代碼

在btaddr下mm,若能build過,Service端就實現好了

 

6.將編譯出的service可執行程序編譯進文件系統
在/device/$(Vender)/$(Product)/$(Product).mk中添加: PRODUCT_PACKAGES += [email protected]

 

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/[email protected]    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;

重新編譯系統進行驗證。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章