1.环境配置 首先将AOSP的源码编译一下,编译步骤详见传送门
编译完成之后,查看:源码根目录/out/host/linux-x86/bin中是否有hidl-gen 工具。
配置环境变量:
1 jackou@ubuntu:~$ vim .bashrc
在末尾添加
export PATH=$PATH:/home/jackou/work_directory/out/host/linux-x86/bin/
2.新建HIDL模块 2.1 新建hal接口文件 在hardware/interfaces目录新建存放接口的目录
创建hal文件,名为IHidlTest.hal
1 2 3 4 5 package android.hardware.hidltest@1.0 ;interface IHidlTest { helloWorld(string name) generates (string result); };
2.2 生成.h和.cpp文件 在根目录下利用hidl-gen生成对应的服务端代码:
1 2 3 4 PACKAGE=android.hardware.hidltest@1.0 LOC=hardware/interfaces/hidltest/1.0/default/ hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
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 #ifndef ANDROID_HARDWARE_HIDLTEST_V1_0_HIDLTEST_H #define ANDROID_HARDWARE_HIDLTEST_V1_0_HIDLTEST_H #include <android/hardware/hidltest/1.0/IHidlTest.h> #include <hidl/MQDescriptor.h> #include <hidl/Status.h> namespace android {namespace hardware {namespace hidltest {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 HidlTest : public IHidlTest { Return<void > helloWorld (const hidl_string& name, helloWorld_cb _hidl_cb) override ; }; extern "C" IHidlTest* HIDL_FETCH_IHidlTest (const char * name) ; } } } } } #endif
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 #include "HidlTest.h" namespace android {namespace hardware {namespace hidltest {namespace V1_0 {namespace implementation {Return<void > HidlTest::helloWorld (const hidl_string& name, helloWorld_cb _hidl_cb) { char buf[100 ]; ::memset (buf,0x00 ,sizeof (buf)); ::snprintf (buf,100 ,"hello world, %s" ,name.c_str()); hidl_string result (buf) ; _hidl_cb(result); return Void(); } IHidlTest* HIDL_FETCH_IHidlTest (const char * ) { return new HidlTest(); } } } } } }
2.3 更新bp文件 使用一下脚本更新bp文件,不知道为什么,我使用的Android P代码,lunch 10产品,使用一下脚本始终不能像博友生成Android.mk文件,只生成了Andorid.bp文件。不过没关系,不影响编译,bp文件也是可以编译的。
1 ./hardware/interfaces/update-makefiles.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Android.bp文件 // This file is autogenerated by hidl-gen -Landroidbp. hidl_interface { name: "android.hardware.hidltest@1.0", root: "android.hardware", vndk: { enabled: true, }, srcs: [ "IHidlTest.hal", ], interfaces: [ "android.hidl.base@1.0", ], gen_java: true, }
标签说明:
name 需要与package name 相同,编译的时候会根据需要生成对应的so 或jar
root 即为与hidl 对应的root name
interfaces 为编译过程中依赖的接口名称,如c 中的shared library
types 为模块中所需要的自定义类型
如果有需要的java 代码可以将 gen_java 设为 true,如果没有(例如passthrough 模式)需要将这里设为false。不过一般通过update_makefiles.sh 就可以自动生成。详细看Android HIDL 中 hidl-gen使用
配置完成之后,编译会在**~/work_directory/out/soong/.intermediates/hardware/interfaces/hidltest/1.0**生成如下文件:
2.4 采取直通模式 将HidlTest.h中的以下注释解开,代码如2.2小节
将HidlTest.cpp中的以下代码注解解开,代码如2.2小节
1 2 3 IHidlTest* HIDL_FETCH_IHidlTest (const char * ) { return new HidlTest(); }
2.5 实现功能 在HidlTest.cpp中实现接口的功能,代码见代码如2.2小节
1 2 3 4 5 6 7 8 9 Return<void > HidlTest::helloWorld (const hidl_string& name, helloWorld_cb _hidl_cb) { char buf[100 ]; ::memset (buf,0x00 ,sizeof (buf)); ::snprintf (buf,100 ,"hello world, %s" ,name.c_str()); hidl_string result (buf) ; _hidl_cb(result); return Void(); }
ok,现在大功告成; 准备开始编译。
2.6 编译模块 在根目录使用以下命令编译模块
1 mmm hardware/interfaces/hidltest/1.0/default/
具有实现的so库有了,我们开始构建binder通信服务。
在default目录创建android.hardware.hidltest@1.0-service.rc 文件,作为启动文件
1 2 3 4 service hidltest_hal_service /vendor/bin/hw/android.hardware.hidltest@1.0-service class hal user system group system
配置服务的名字为hidltest_hal_service。
2.8 编写service文件 1 2 3 4 5 6 7 8 9 10 #define LOG_TAG "android.hardware.hidltest@1.0-service" #include <android/hardware/hidltest/1.0/IHidlTest.h> #include <hidl/LegacySupport.h> using android::hardware::hidltest::V1_0::IHidlTest;using android::hardware::defaultPassthroughServiceImplementation;int main () { printf ("start hidltest service" ); return defaultPassthroughServiceImplementation<IHidlTest>(); }
2.9 在Android.bp中添加对服务器的编译: 1 vim hardware/interfaces/hidltest/1.0/default/Android.bp
在Android.bp中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cc_binary { name: "android.hardware.hidltest@1.0-service", relative_install_path: "hw", proprietary: true, init_rc: ["android.hardware.hidltest@1.0-service.rc"], srcs: ["service.cpp"], shared_libs: [ "liblog", "libcutils", "libdl", "libbase", "libutils", "libhardware", "libhidlbase", "libhidltransport", "android.hardware.hidltest@1.0", ], }
2.10 编写manifest.xml文件 为了使客户端能够调用服务端的代码需要在manifest.xml中添加服务:在device/qcom/msm8996/manifest.xml文件最后添加:
1 2 3 4 5 6 7 8 9 10 <hal format ="hidl" > <name > android.hardware.hidltest</name > <transport > passthrough</transport > <version > 1.0</version > <interface > <name > IHidlTest</name > <instance > default</instance > </interface > </hal >
或者在车机 /vendor/etc/vintf/manifest.xml中
2.11 再次编译模块 1 mmm hardware/interfaces/hidltest/1.0/default/
最后生成的文件
out/target/product/generic_x86_64/vendor/lib64/hw/android.hardware.hidltest@1.0-impl.so
out/target/product/generic_x86_64/vendor/bin/hw/android.hardware.hidltest@1.0-service
out/target/product/generic_x86_64/system/lib64/vndk-28/android.hardware.hidltest@1.0.so
2.12 编写C++客户端 在hardware/interfaces/hidltest/1.0/建立test目录,用于存储c++客户端代码。
创建HidlTestClient.cpp文件,并且编写客户端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <android/hardware/hidltest/1.0/IHidlTest.h> #include <hidl/Status.h> #include <hidl/LegacySupport.h> #include <utils/misc.h> #include <hidl/HidlSupport.h> #include <stdio.h> using ::android::hardware::hidl_string;using ::android::sp;using android::hardware::hidltest::V1_0::IHidlTest;int main () { android::sp<IHidlTest> service = IHIdlTest::getService(); if (service == nullptr ){ printf ("Failed to get service\n" ); return -1 ; } service->helloWorld("HidlTest" , [&](hidl_string result){ printf ("%s\n" , result.c_str()); }); return 0 ; }
2.13 编写客户端编译脚本 在hardware/interfaces/hidltest/1.0/test目录下,创建Android.bp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cc_binary { relative_install_path: "hw", defaults: ["hidl_defaults"], name: "hidltest_client", proprietary: true, srcs: ["HidlTestClient.cpp"], shared_libs: [ "liblog", "libhardware", "libhidlbase", "libhidltransport", "libutils", "android.hardware.hidltest@1.0", ], }
2.14 编译模块 1 mmm hardware/interfaces/hidltest/1.0/
out/target/product/generic_x86_64/system/framework/oat/x86_64/目录下生成android.hardware.hidltest-V1.0-java.odex可执行文件
2.15 编写Android app端代码 2.15.1 取的jar包 从2.3中~/work_directory/out/soong/.intermediates/hardware/interfaces/hidltest/1.0/android.hardware.hidltest-V1.0-java/android_common/combined目录拿到Android端使用的jar包。
2.15.2 建立AS工程 由于HIDL调用需要java 8,所以在build.gradle中加入以下配置
1 2 3 4 5 6 7 android { ...... compileOptions { targetCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8 } }
2.15.3 编写代码 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 public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private Button mShow; private TextView mTextShow; IHidlTest mService; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextShow = findViewById(R.id.textView); mShow = findViewById(R.id.button); String content; try { mService = IHidlTest.getService(); if (mService == null ) { Log.e(TAG, "service is null" ); return ; } content = mService.helloWorld("hello world!" ); mTextShow.setText(content); } catch (RemoteException e) { e.printStackTrace(); } mShow.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View v) { try { String content = mService.helloWorld("hello world!" + System.currentTimeMillis()); mTextShow.setText(content); } catch (RemoteException e) { e.printStackTrace(); } } }); } }
编译上面demo工程,生成apk文件,准备在目标板子上运行。
至此,所有准备工作已经做完了。
2.16 将目标文件烧写到车机 需要准备的文件
base path: ~/work_directory/out/target/product/generic_x86_64
abstract path:
车机中的manifest.xml修改之后push到原来的目录
2.16.1 push路径说明
android.hardware.hidltest@1.0-impl.so –> /vendor/lib64/hw
android.hardware.hidltest@1.0.so –> /system/lib64
hidltest_client –> /vendor/bin/hw
android.hardware.hidltest@1.0-service –> /vendor/bin/hw
manifest.xml –> /vendor/etc/vintf
2.16.2 安装apk
adb install -r /本地路径/app-debug.apk
2.17 启动服务,测试功能
1.启动Hidl模块服务 ./vendor/bin/hw/android.hardware.hidltest@1.0-service
2.启动客户端 ./vendor/bin/hw/hidltest_client
3.运行apk看界面现象
Notice :HAL回调实现下一小节叙述,或者见参考文献3
参考文献 1. Android HIDL 实例
2. HIDL实战笔记
3. Android HIDL学习(3) —- 注册回调