android 裏邊添加hidl服務

 

筆者在Android 9 通過以下方式添加hidl服務,理論上對Android 8/9/10 都適用,
對於爲何要有hidl這個東西以及如何添加hidl服務,google在https://source.android.google.cn/devices/architecture/hidl 裏邊有說明,
只是添加步驟不夠詳細,本人之前踩過一些坑折騰了好一會兒才添加成功,所以纔想寫這篇文章和同學們一起交流學習,本文目前只描述如何做不描述底層原理(底層也是用來binder),文章內容全部是基於android開源技術。

假設咱們要創建的hidl服務名字test,項目或公司的名字爲vendorname,一般作爲vendor咱們添加的服務放在/vendor/yourvendorname/目錄下。
 

1,創建目錄和接口文件

在 android/vendor/yourvendorname 底下創建test目錄,(若讀者下載的是原生代碼,沒有vendor和yourvendorname,麻煩分別創建);

由於是首次添加服務,在test 目錄下創建名字爲1.0的文件夾,表示第一個版本,
在1.0 目錄下需要添加2個文件, Itest.hal 和 types.hal(不自定義結構體的話可以不需要創建),
ITest.hal裏邊定義test服務對外開放的接口,types.hal定義自定義的結構體類型,這2個的語法可以參考官網說明。
比如咱們的test服務要對外提供一個doSomething()的hidl接口,不自定義結構體,

//ITest.hal
package [email protected];

//import package (如果需要用到別的地方定義的類,可以import)

interface ITest {
    doSomething();//沒有參數沒有返回值
};

2,用hidl-gen 生成Android.bp, Test.cpp, Test.h

 

接着用hidl-gen 創建 Android.bp以及.cpp和.h文件,(若讀者創建的test文件夾和相關文件是放在hardware/interface下,可以直接用
該目錄下的update-makefiles.sh 腳本生成)
hidl-gen 工具位於 ./out/soong/host/linux-x86/bin/hidl-gen,
source, lunch 後可以直接在 android根目錄下執行,(筆者以下幾條命令也是基於android根目錄執行),

hidl-gen -O ""  -Landroidbp  -r android.vendor:vendor [email protected]
[email protected]
LOC=android根目錄路徑/vendor/yourvendorname/test/1.0/default/   (即  "test絕對路徑 + /1.0/default/")
hidl-gen -o $LOC -Lc++-impl -randroid.vendor:vendor  -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.vendor:vendor -randroid.hidl:system/libhidl/transport $PACKAGE

 


執行完就會生成2個Android.bp(筆者有需要的話可以自行將default底下的那個改成Android.mk),
default文件夾以及Test.cpp,Test.h,裏邊包含test類和對其對外接口的定義,比如咱們目前的2個文件長這個樣子,

//Test.h
#ifndef ANDROID_VENDOR_YOURVENDORNAME_TEST_V1_0_TEST_H
#define ANDROID_VENDOR_YOURVENDORNAME_TEST_V1_0_TEST_H

#include <android/vendor/yourvendorname/test/1.0/ITest.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>

namespace android {
namespace vendor {
namespace yourvendorname {
namespace test {
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;

struct Test : public ITest {
    // Methods from ::android::vendor::yourvendorname::test::V1_0::ITest follow.
    Return<void> doSomething() override;

    // Methods from ::android::hidl::base::V1_0::IBase follow.

};

// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" ITest* HIDL_FETCH_ITest(const char* name);

}  // namespace implementation
}  // namespace V1_0
}  // namespace test
}  // namespace yourvendorname
}  // namespace vendor
}  // namespace android

#endif  // ANDROID_VENDOR_YOURVENDORNAME_TEST_V1_0_TEST_H
//Test.cpp
#include "Test.h"

namespace android {
namespace vendor {
namespace yourvendorname {
namespace test {
namespace V1_0 {
namespace implementation {

// Methods from ::android::vendor::yourvendorname::test::V1_0::ITest follow.
Return<void> Test::doSomething() {
    // TODO implement
    return Void();
}


// Methods from ::android::hidl::base::V1_0::IBase follow.

//ITest* HIDL_FETCH_ITest(const char* /* name */) {
    //return new Test();
//}
//
}  // namespace implementation
}  // namespace V1_0
}  // namespace test
}  // namespace yourvendorname
}  // namespace vendor
}  // namespace android

3,添加接口實現,rc文件,服務註冊文件

3,添加接口實現,rc文件,服務註冊文件 
接下來就可以往test類添加相關的實現了,添加完後,由於咱們這是一個hidl服務,
(1)所以需要寫一個main函數,將該test服務註冊到hwservicemanager裏邊。(一般文件命名爲service.cpp)
   然後在main裏邊起一個線程程在 IPCThreadState 裏邊去監聽hwbinder節點(即監聽客戶端請求)然後處理請求,
(2)然後還需要改一下default底下的Android.bp,編出一個bin文件,
(3)然後還需要編寫[email protected] 在android系統啓動的時候執行該bin文件。

 

//1.0/default/Android.bp
cc_binary {
    name: "[email protected]",
    relative_install_path: "hw",
    vendor: true,
    init_rc: ["[email protected]"],
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
        "-Wno-unused-parameter",
    ],
    srcs: ["service.cpp",
	    "Test.cpp",      
	],

    shared_libs: [
        "liblog",
        "libcutils",
        "libdl",
        "libbase",
        "libutils",
        "libhidlbase",
        "libhidltransport",
        "[email protected]",
    ],
}

//1.0/Android.bp
// This file is autogenerated by hidl-gen -Landroidbp.

hidl_interface {
    name: "[email protected]",
    root: "android.vendor",
    srcs: [
        "ITest.hal",
    ],
    interfaces: [
        "[email protected]",
    ],
    gen_java: true,
}

//hidl_package_root {
//    name: "android.vendor",
//    path: "vendor",
//}

subdirs = ["default"]
//service.cpp
#define LOG_TAG "[email protected]"

#include <android-base/logging.h>
#include <android/vendor/yourvendorname/test/1.0/ITest.h>
#include <hidl/LegacySupport.h>
#include "Test.h"



using android::vendor::yourvendorname::test::V1_0::ITest;
using android::vendor::yourvendorname::test::V1_0::implementation::Test;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;

int main() {

    configureRpcThreadpool(1 /*threads*/, true /*willJoin*/);
 
    sp<ITest> test = new Test();
 
    //註冊成爲一個服務
    if(android::OK !=  test->registerAsService()) { 
        LOG(ERROR) << "=====>lkh test register failed!!!";
        return -1; // or handle error
     } else {
	LOG(ERROR) << "=====>lkh test register success !!!";
     }
 
    // Adds this thread to the threadpool, resulting in one total
    // thread in the threadpool. We could also do other things, but
    // would have to specify 'false' to willJoin in configureRpcThreadpool.
    //開始監聽請求
    joinRpcThreadpool();
    
    return -1;
}

#rc file
service vendor.test  /vendor/bin/hw/[email protected]
    class hal
    user system
    group system

4,編譯

然後可以mm編譯了,編出來的在out目錄下的東西爲:
system/lib/[email protected]
system/lib/[email protected]
system/lib64/[email protected]
system/lib64/[email protected]
vendor/etc/init/[email protected]
vendor/bin/hw/[email protected]

 

note: 若編譯過程出現如下類似錯誤,
FAILED: out/soong/build.ninja
out/soong/.bootstrap/bin/soong_build -t -l out/.module_paths/Android.bp.list -b out/soong -n out -d out/soong/build.ninja.d -o out/soong/build.ninja Android.bp
error: vendor/yourvendorname/test/1.0/Android.bp:5:9: module "[email protected]_interface": root: Root, android, for [email protected] must be a prefix.
error: vendor/yourvendorname/test/1.0/Android.bp:9:15: module "[email protected]_interface": interfaces: 
Cannot find package root specification for package root 'android' needed for module '[email protected]'. 
Either this is a mispelling of the package root, or a new hidl_package_root module needs to be added.
 For example, you can fix this error by adding the following to <some path>/Android.bp:

hidl_package_root {
    name: "android",
    path: "<some path>",
}

可在1.0目錄下的Android.bp添加如下內容嘗試解決:
hidl_package_root {
    name: "android.vendor",
    path: "vendor",
}

5,啓動運行

將4裏邊生成的那些東西push到咱們的android對應的路徑下,然後reboot,

就可以看見咱們的服務已經起來了

 

lshal 也可以看見  [email protected]::ITest/default 已經註冊到hwservicemanager了

 

 

6,客戶端調用

Android.bp/Android.mk
共享庫項裏邊添加 
  [email protected],libbase,libhardware,libhidlbase,libhidltransport,libhwbinder

  //再包含相關頭文件
  #include <android/vendor/yourvendorname/test/1.0/ITest.h>
  //懶的寫全稱的話再加個using namespace
  using namespace android::vendor::yourvendorname::test::V1_0;
  
  //獲取服務
  sp<ITest> test = ITest::getService();
  //調用接口
  test->doSomething();
  

 

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