rk3368 Android9.0 HIDL调试记录
1 2 3 | Platform: RK3368 OS: Android 9.0 Kernel: 4.4.194 |
文章目录
- rk3368 Android9.0 HIDL调试记录
-
- 1. 使用hidl-gen工具生成接口
-
- 1.1 hidl-gen使用方法
- 1.2 创建HIDL文件
- 1.3 使用hidl-gen工具生成HIDL相关文件
- 2. 修改代码
-
- 2.1 创建service代码
- 2.2 修改Android.bp添加编译service
- 2.3 添加启动service的init.rc文件
- 2.4 修改生成的代码
- 2.5 添加本地C++测试代码
- 3. 编译测试
-
- 3.1 mmm单独模块编译:
- 3.2 Native测试
- 3.3 Android APP java测试
在Android 8.0以后,低层已重新编写以采用更加模块化的新架构。必须支持使用 HIDL 语言编写的 HAL,下面列出了一些例外情况。这些 HAL 可以是绑定式 HAL 也可以是直通式 HAL.
绑定式 HAL 以 HAL 接口定义语言 (HIDL) 或 Android 接口定义语言 (AIDL) 表示的 HAL。这些 HAL 取代了早期 Android 版本中使用的传统 HAL 和旧版 HAL。在绑定式 HAL 中,Android 框架和 HAL 之间通过 Binder 进程间通信 (IPC) 调用进行通信。所有在推出时即搭载了 Android 8.0 或更高版本的设备都必须只支持绑定式 HAL。
直通式 HAL 以 HIDL 封装的传统 HAL 或旧版 HAL。这些 HAL 封装了现有的 HAL,可在绑定模式和 Same-Process(直通)模式下使用。升级到 Android 8.0 的设备可以使用直通式 HAL。
此调试记录为绑定式 HAL;
1. 使用hidl-gen工具生成接口
1.1 hidl-gen使用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $ hidl-gen -h usage: hidl-gen [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface root>)+ [-v] [-d <depfile>] FQNAME... Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output. -h: Prints this menu. -L <language>: The following options are available: check : Parses the interface to see if valid but doesn't write any files. c++ : (internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces. c++-headers : (internal) Generates C++ headers for interface files for talking to HIDL interfaces. c++-sources : (internal) Generates C++ sources for interface files for talking to HIDL interfaces. export-header : Generates a header file from @export enumerations to help maintain legacy code. c++-impl : Generates boilerplate implementation of a hidl interface in C++ (for convenience). c++-impl-headers: c++-impl but headers only c++-impl-sources: c++-impl but sources only c++-adapter : Takes a x.(y+n) interface and mocks an x.y interface. c++-adapter-headers: c++-adapter but helper headers only c++-adapter-sources: c++-adapter but helper sources only c++-adapter-main: c++-adapter but the adapter binary source only java : (internal) Generates Java library for talking to HIDL interfaces in Java. java-constants : (internal) Like export-header but for Java (always created by -Lmakefile if @export exists). vts : (internal) Generates vts proto files for use in vtsd. makefile : (removed) Used to generate makefiles for -Ljava and -Ljava-constants. androidbp : (internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter. androidbp-impl : Generates boilerplate bp files for implementation created with -Lc++-impl. hash : Prints hashes of interface in `current.txt` format to standard out. -O <owner>: The owner of the module for -Landroidbp(-impl)?. -o <output path>: Location to output files. -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd. -r <package:path root>: E.g., android.hardware:hardware/interfaces. -v: verbose output. -d <depfile>: location of depfile to write to. |
1.2 创建HIDL文件
- 新建目录vendor/sample/hardware/interfaces/helloworld/1.0
- 创建文件: IHelloWorld.hal IHelloWorldCallback.hal types.hal
不要直接在Android源码目录hardware/interfaces下面添加和修改接口,在API锁定分支中不允许更改VNDK库列表.
其中vendor/sample/hardware/interfaces就是hidl的root path了.
helloworld/1.0/IHelloWorld.hal
1 2 3 4 5 6 7 8 9 10 | package [email protected]; import IHelloWorldCallback; interface IHelloWorld { initial(); getInt() generates (int32_t i); setInt(int32_t val) generates (Result error); oneway setCallback(IHelloWorldCallback callback); }; |
helloworld/1.0/IHelloWorldCallback.hal
1 2 3 4 5 |
helloworld/1.0/types.hal
1 2 3 4 5 6 7 8 9 10 11 12 | package [email protected]; enum Result : int32_t { OK, UNKNOWN, INVALID_ARGUMENTS, }; struct Event { uint32_t type; uint32_t code; uint32_t value; }; |
- 指定HIDL包根目录
添加文件vendor/sample/hardware/interfaces/Android.bp
1 2 3 4 | hidl_package_root { name: "sample.hardware", path: "vendor/sample/hardware/interfaces", } |
如果不指定HIDL包根目录,编译会报错:Cannot find package root specification
1 2 3 4 5 6 | interfaces: Cannot find package root specification for package root 'sample.hardware' 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: "sample.hardware", path: "<some path>", } |
- 生成HIDL哈希
每个软件包根目录(即映射到 hardware/interfaces 的 android.hardware 或映射到 vendor/foo/hardware/interfaces 的 vendor.foo)都必须包含一个列出所有已发布 HIDL 接口文件的 current.txt 文件。
1 | $ hidl-gen -Lhash -rsample.hardware:vendor/sample/hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected]> vendor/sample/hardware/interfaces/current.txt |
1.3 使用hidl-gen工具生成HIDL相关文件
- 使用hidl-gen生成C++文件
1 | $ hidl-gen -o vendor/sample/hardware/interfaces/helloworld/1.0/default -Lc++-impl -rsample.hardware:vendor/sample/hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected] |
把生成的下面两个不用的文件删除:
helloworld/1.0/default/HelloWorldCallback.cpp
helloworld/1.0/default/HelloWorldCallback.h
- 使用hidl-gen生成helloworld/1.0/default/Android.bp
1 | $ hidl-gen -o vendor/sample/hardware/interfaces/helloworld/1.0/default -Landroidbp-impl -rsample.hardware:vendor/sample/hardware/interfaces -randroid.hidl:system/libhidl/transport [email protected] |
- 使用system/tools/hidl/update-makefiles-helper.sh生成helloworld/1.0/Android.bp
1 2 | $ source $ANDROID_BUILD_TOP/system/tools/hidl/update-makefiles-helper.sh $ do_makefiles_update sample.hardware:vendor/sample/hardware/interfaces android.hardware:hardware/interfaces android.hidl:system/libhidl/transport |
helloworld/1.0/Android.bp内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // This file is autogenerated by hidl-gen -Landroidbp. hidl_interface { name: "[email protected]", root: "sample.hardware", srcs: [ "types.hal", "IHelloWorld.hal", "IHelloWorldCallback.hal", ], interfaces: [ "[email protected]", ], types: [ "Event", "Result", ], gen_java: true, } |
- 为device manifest添加hal接口
由hwservicemanager去解析并将服务启动;
device/rockchip/$TARGET_PRODUCT/manifest.xml
1 2 3 4 5 6 7 8 9 | <hal format="hidl"> <name>sample.hardware.helloworld</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IHelloWorld</name> <instance>default</instance> </interface> </hal> |
然后完整编译一下Android,更新manifest.xml文件:
1 | out/target/product/$TARGET_PRODUCT/vendor/etc/vintf/manifest.xml |
如果不更新device manifest,测试程序会找不到服务端,hwservicemanager会报以下错误:
W hwservicemanager: getTransport: Cannot find entry [email protected]::IHelloWorld/default in either framework or device manifest.
2. 修改代码
2.1 创建service代码
hardware/interfaces/sample/1.0/default/service.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #define LOG_TAG "[email protected]" #include <android-base/logging.h> #include <hidl/HidlTransportSupport.h> #include "HelloWorld.h" using android::OK; using android::sp; using android::status_t; using android::hardware::configureRpcThreadpool; using android::hardware::joinRpcThreadpool; using sample::hardware::helloworld::V1_0::IHelloWorld; using sample::hardware::helloworld::V1_0::implementation::HelloWorld; int main(int /* argc */, char ** /* argv */) { ALOGD("HAL Service is starting."); sp<IHelloWorld> service = new HelloWorld(); configureRpcThreadpool(1, true /*callerWillJoin*/); status_t status = service->registerAsService(); if (status != OK) { LOG_ALWAYS_FATAL("Could not register service for HelloWorld HAL Iface (%d).", status); return -1; } ALOGD("Register as service ready."); joinRpcThreadpool(); return 1; // joinRpcThreadpool shouldn't exit } |
2.2 修改Android.bp添加编译service
hardware/interfaces/sample/1.0/default/Android.bp
将cc_library_shared节点proprietary: true改为vendor: true;
删除relative_install_path: “hw”,目的是将[email protected]编译安装到vendor/lib64目录下面,如果vendor/lib64/hw下面,运行服务时因VNDK规则限制,会报以下错误:
F linker : CANNOT LINK EXECUTABLE “./vendor/bin/hw/[email protected]”: library “[email protected]” not found
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | cc_library_shared { name: "[email protected]", vendor: true, srcs: [ "HelloWorld.cpp", ], shared_libs: [ "liblog", "libhidlbase", "libhidltransport", "libutils", "[email protected]", ], } cc_binary { name: "[email protected]", defaults: ["hidl_defaults"], vendor: true, relative_install_path: "hw", init_rc: ["[email protected]"], srcs: ["service.cpp"], shared_libs: [ "libcutils", "libhidlbase", "libhidltransport", "liblog", "libutils", "libhardware", "[email protected]", "[email protected]", ], } |
2.3 添加启动service的init.rc文件
hardware/interfaces/sample/1.0/default/[email protected]
1 2 3 4 |
2.4 修改生成的代码
helloworld/1.0/default/HelloWorld.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #ifndef SAMPLE_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H #define SAMPLE_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H #include <sample/hardware/helloworld/1.0/IHelloWorld.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace sample { namespace hardware { namespace helloworld { 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 HelloWorld : public IHelloWorld { Return<void> initial() override; Return<int32_t> getInt() override; Return<::sample::hardware::helloworld::V1_0::Result> setInt(int32_t val) override; Return<void> setCallback(const sp<::sample::hardware::helloworld::V1_0::IHelloWorldCallback> &callback) override; static void *pollThreadWrapper(void *me); void pollThreadEntry(); private: pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER; pthread_t mPollThread; bool mRunning; std::vector<sp<IHelloWorldCallback>> mCallbacks; }; } // namespace implementation } // namespace V1_0 } // namespace helloworld } // namespace hardware } // namespace sample #endif // SAMPLE_HARDWARE_HELLOWORLD_V1_0_HELLOWORLD_H |
helloworld/1.0/default/HelloWorld.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #define LOG_TAG "[email protected]" #include <android-base/logging.h> #include <log/log.h> #include "HelloWorld.h" namespace sample { namespace hardware { namespace helloworld { namespace V1_0 { namespace implementation { Return<void> HelloWorld::initial() { ALOGD("%s", __FUNCTION__); if (mRunning) return Void(); mRunning = true; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&mPollThread, &attr, pollThreadWrapper, this); pthread_attr_destroy(&attr); return Void(); } Return<int32_t> HelloWorld::getInt() { ALOGD("%s", __FUNCTION__); return int32_t{666}; } Return<::sample::hardware::helloworld::V1_0::Result> HelloWorld::setInt(int32_t val) { ALOGD("%s %d", __FUNCTION__, val); return ::sample::hardware::helloworld::V1_0::Result{}; } void *HelloWorld::pollThreadWrapper(void *me) { static_cast<HelloWorld *>(me)->pollThreadEntry(); return NULL; } void HelloWorld::pollThreadEntry() { mRunning = true; ALOGD("%s enter", __FUNCTION__); Event event; event.type = 0; event.code = 0; event.value = 0; while (mRunning) { event.code++; event.type++; event.value++; sleep(1); ALOGD("%s event %04x %04x %04x\n", __FUNCTION__, event.type, event.code, event.value); pthread_mutex_lock(&mLock); if (!mCallbacks.empty()) { std::vector<sp<IHelloWorldCallback>>::iterator it; for (it = mCallbacks.begin(); it != mCallbacks.end();) { sp<IHelloWorldCallback> callback = *it; Return<void> ret = callback->onEvent(event); if (!ret.isOk()) { ALOGE("error %s", ret.description().c_str()); it = mCallbacks.erase(it); } else { it++; } } } pthread_mutex_unlock(&mLock); } ALOGD("%s exit", __FUNCTION__); } Return<void> HelloWorld::setCallback(const sp<::sample::hardware::helloworld::V1_0::IHelloWorldCallback> &callback) { ALOGD("%s", __FUNCTION__); pthread_mutex_lock(&mLock); if (callback != nullptr) { mCallbacks.push_back(callback); } pthread_mutex_unlock(&mLock); return Void(); } } // namespace implementation } // namespace V1_0 } // namespace helloworld } // namespace hardware } // namespace sample |
2.5 添加本地C++测试代码
helloworld/1.0/test/Android.bp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | cc_binary { name: "sample.hardware.helloworld_hidl_hal_test", vendor: true, srcs: ["test.cpp"], shared_libs: [ "libhidlbase", "libhidltransport", "liblog", "libutils", "libhardware", "[email protected]", ], } |
helloworld/1.0/test/test.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #define LOG_TAG "sample.hardware.helloworld_hidl_hal_test" #include <android-base/logging.h> #include <hidl/HidlTransportSupport.h> #include <log/log.h> #include <sample/hardware/helloworld/1.0/IHelloWorld.h> #include <sample/hardware/helloworld/1.0/types.h> using ::android::sp; using ::android::hardware::Return; using ::android::hardware::Void; using ::sample::hardware::helloworld::V1_0::Event; using ::sample::hardware::helloworld::V1_0::IHelloWorld; using ::sample::hardware::helloworld::V1_0::IHelloWorldCallback; using ::sample::hardware::helloworld::V1_0::Result; class HelloWorldCallback : public IHelloWorldCallback { public: HelloWorldCallback() { printf("%s\n", __FUNCTION__); } ~HelloWorldCallback() { printf("%s\n", __FUNCTION__); } Return<void> onEvent(const Event &event) { printf("%s %04x %04x %04x\n", __FUNCTION__, event.type, event.code, event.value); return Void(); } }; int main(int /* argc */, char ** /* argv */) { sp<IHelloWorld> service = IHelloWorld::getService(); if (service == nullptr) { printf("Failed to get service\n"); return -1; } printf("initial\n"); service->initial(); int ret = service->getInt(); printf("getInt %d\n", ret); Result result = service->setInt(888); printf("setInt result=%d\n", result); sp<IHelloWorldCallback> callback = new HelloWorldCallback(); printf("setCallback\n"); service->setCallback(callback); while (1) { sleep(1); } return 0; } |
3. 编译测试
3.1 mmm单独模块编译:
1 | $ mmm vendor/sample/hardware/interfaces/helloworld/1.0/ |
- 编译hal文件生成的中间代码位于out/soong/.intermediates/vendor/sample/hardware/interfaces/helloworld/1.0/:
1 2 3 4 5 6 7 8 9 10 11 12 | default [email protected] [email protected] [email protected]_genc++ [email protected] [email protected]_genc++ [email protected]_genc++_headers [email protected]_genc++ [email protected]_genc++_headers sample.hardware.helloworld-V1.0-java sample.hardware.helloworld-V1.0-java_gen_java test |
"[email protected]_genc++"目录里面可以发现hal文件转换成了C++源码 ,里面就包含Binder Bn端,Binder Bp端的代码.不用像非Project Treble项目那样需要自己写Binder Bn端,Binder Bp端的代码.体会到了谷歌的良苦用心.
- 编译最终会在out/target/product/$TARGET_PRODUCT/目录下面生成了以下文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | out/target/product/$TARGET_PRODUCT/system/lib/[email protected] out/target/product/$TARGET_PRODUCT/system/lib/[email protected] out/target/product/$TARGET_PRODUCT/system/lib64/[email protected] out/target/product/$TARGET_PRODUCT/system/lib64/[email protected] out/target/product/$TARGET_PRODUCT/system/framework/sample.hardware.helloworld-V1.0-java.jar out/target/product/$TARGET_PRODUCT/system/framework/oat/arm/sample.hardware.helloworld-V1.0-java.odex out/target/product/$TARGET_PRODUCT/system/framework/oat/arm/sample.hardware.helloworld-V1.0-java.vdex out/target/product/$TARGET_PRODUCT/system/framework/oat/arm64/sample.hardware.helloworld-V1.0-java.odex out/target/product/$TARGET_PRODUCT/system/framework/oat/arm64/sample.hardware.helloworld-V1.0-java.vdex out/target/product/$TARGET_PRODUCT/vendor/lib/[email protected] out/target/product/$TARGET_PRODUCT/vendor/lib/[email protected] out/target/product/$TARGET_PRODUCT/vendor/lib/[email protected] out/target/product/$TARGET_PRODUCT/vendor/lib64/[email protected] out/target/product/$TARGET_PRODUCT/vendor/lib64/[email protected] out/target/product/$TARGET_PRODUCT/vendor/lib64/[email protected] out/target/product/$TARGET_PRODUCT/vendor/bin/hw/[email protected] out/target/product/$TARGET_PRODUCT/vendor/bin/sample.hardware.helloworld_hidl_hal_test out/target/product/$TARGET_PRODUCT/vendor/etc/init/[email protected] |
3.2 Native测试
- 将编译好的库和bin文件复制到设备中:
1 2 3 4 5 6 | $ adb root $ adb remount $ adb push out/target/product/$TARGET_PRODUCT/vendor/lib64/[email protected] /vendor/lib64/[email protected] $ adb push out/target/product/$TARGET_PRODUCT/vendor/lib64/[email protected] /vendor/lib64/[email protected] $ adb push out/target/product/$TARGET_PRODUCT/vendor/bin/hw/[email protected] /vendor/bin/hw/[email protected] $ adb push out/target/product/$TARGET_PRODUCT/vendor/bin/sample.hardware.helloworld_hidl_hal_test /vendor/bin/sample.hardware.helloworld_hidl_hal_test |
- 启动服务和测试
1 2 3 4 5 6 7 8 9 10 | # ./vendor/bin/hw/[email protected]& # sample.hardware.helloworld_hidl_hal_test initial getInt 666 setInt result=0 HelloWorldCallback setCallback onEvent 0001 0001 0001 onEvent 0002 0002 0002 onEvent 0003 0003 0003 |
3.3 Android APP java测试
Android Studio中将out/soong/.intermediates/vendor/sample/hardware/interfaces/helloworld/1.0/sample.hardware.helloworld-V1.0-java/android_common/combined/sample.hardware.helloworld-V1.0-java.jar 复制到APP工程的libs目录下面,然后将此jar包导入工程就可以使用了,java使用就是这么简单,连JNI都不用自己写了;
不要用/system/framework/sample.hardware.helloworld-V1.0-java.jar这个jar包,这是Dex优化剥离了class文件后的jar;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package com.example.helloworld; import android.app.Activity; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; import sample.hardware.helloworld.V1_0.Event; import sample.hardware.helloworld.V1_0.IHelloWorld; import sample.hardware.helloworld.V1_0.IHelloWorldCallback; public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { IHelloWorld helloWorld = IHelloWorld.getService(); helloWorld.initial(); int ret = helloWorld.getInt(); Log.d(TAG, "getInt=" + ret); helloWorld.setInt(888); helloWorld.setCallback(new HelloWorldCallback()); } catch (RemoteException e) { e.printStackTrace(); } } static class HelloWorldCallback extends IHelloWorldCallback.Stub { @Override public void onEvent(Event event) throws RemoteException { Log.d(TAG, "onEvent type=" + event.type + ", code=" + event.code + ", value=" + event.value); } } } |