筆者在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();