Android hidl开发简单教程
开发前的准备
开发前的准备
关于hidl的前世今生就不多说了,网上百度就挺多的了,主要是我也不是很懂,哈哈哈,这个只是记录一下我在按照网上的教程开发hidl的时候遇到的一些问题,然后说一下我在跟着别人教程学习的时候遇到过的一些问题,改正后成功的例子,希望能对大家学习有一点点帮助.
开发hidl我们首先需要:
①Android的编译环境
②编译过的Android源码(我的是Android 10)
③Android 设备(我的是手机)
第一步:创建文件夹路径和.hal文件
为这个代码想一个好听的名字,我们就叫xiaoming吧,然后相应目录下创建文件夹,如下:
// 在你的Android源码的hardware/interfaces/目录下创建
mkdir -p xiaoming/1.0/default
然后,在你的1.0目录下创建Ixiaoming.hal文件
vim IXiaoming.hal
在里面输入:
1 package android.hardware.xiaoming@1.0;
2
3 interface IXiaoming {
4 helloWorld(string name) generates (string result);
5 };
这里面只有一个简单的hellowork程序,实现会在下面介绍.
创建完成后的文件路径是这个样子的:
.
└── 1.0
├── default
└── IXiaoming.hal
第二步:使用hidl-gen工具
hidl-gen工具是Google在Android 8.1改变HAL之后,为了帮助开发者生成一些HAL层的相关代码框架和代码实例,方便开发者使用.
首先执行以下代码:(需要在源码根目录下root权限执行)
1 PACKAGE=android.hardware.xiaoming@1.0
2 LOC=hardware/interfaces/xiaoming/1.0/default/
3 make hidl-gen
4 hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
5 hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
执行完上面程序后更新以下你的代码目录的Android.bp文件:
./hardware/interfaces/update-makefiles.sh
这个update-makefiles.sh就是Google提供的一个可以自动更新的Android.bp的一个脚本,源码根目录下执行就行了,执行完成后你的目录框架应该是这个样子的:
.
└── 1.0
├── Android.bp
├── default
│ ├── Android.bp
│ ├── Xiaoming.cpp
│ └── Xiaoming.h
└── IXiaoming.hal
然后在你的default目录下创建两个新文件:
1 touch android.hardware.xiaoming@1.0-service.rc
2 touch service.cpp
创建完成后的目录就变成了:
.
└── 1.0
├── Android.bp
├── default
│ ├── Android.bp
│ ├── android.hardware.xiaoming@1.0-service.rc
│ ├── service.cpp
│ ├── Xiaoming.cpp
│ └── Xiaoming.h
└── IXiaoming.hal
第三步:HAL共享库的实现
主要是修改刚刚生成的Xiaoming.cpp和Xiaoming.h文件,我们先打开我们的Xiaoming.h文件,将选择实现Passthrough方式的代码的注释去掉就行了,去掉后如下:
1 // FIXME: your file license if you have one
2
3 //#pragma once
4
5 #ifndef ANDROID_HARDWARE_NARUTO_V1_0_XIAOMING_H
6 #define ANDROID_HARDWARE_NARUTO_V1_0_XIAOMING_H
7
8
9 #include <android/hardware/xiaoming/1.0/IXiaoming.h>
10 #include <hidl/MQDescriptor.h>
11 #include <hidl/Status.h>
12
13 namespace android {
14 namespace hardware {
15 namespace xiaoming {
16 namespace V1_0 {
17 namespace implementation {
18
19 using ::android::hardware::hidl_array;
20 using ::android::hardware::hidl_memory;
21 using ::android::hardware::hidl_string;
22 using ::android::hardware::hidl_vec;
23 using ::android::hardware::Return;
24 using ::android::hardware::Void;
25 using ::android::sp;
26
27 struct Xiaoming : public IXiaoming {
28 // Methods from ::android::hardware::xiaoming::V1_0::IXiaoming follow.
29 Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
30
31 // Methods from ::android::hidl::base::V1_0::IBase follow.
32
33 };
34
35 // FIXME: most likely delete, this is only for passthrough implementations
36 extern "C" IXiaoming* HIDL_FETCH_IXiaoming(const char* name);
37
38 } // namespace implementation
39 } // namespace V1_0
40 } // namespace xiaoming
41 } // namespace hardware
42 } // namespace android
43
44
45 #endif //ANDROID_HARDWARE_NARUTO_V1_0_XIAOMING_H
HIDL的实现方式有两个,一个是Binderized模式,另外一个是Passthrough模式,传说这两个实现方式没多大区别的,我也不知道,因为我也是一个菜鸡.
然后打开Xiaoming.cpp文件,然后将HIDL_FETCH的注释去掉,再增加一个hellowork函数的实现就行了,就是一个简单的字符拼接.修改后如下.
1 // FIXME: your file license if you have one
2
3 #include "Xiaoming.h"
4
5 namespace android {
6 namespace hardware {
7 namespace xiaoming {
8 namespace V1_0 {
9 namespace implementation {
10
11 // Methods from ::android::hardware::xiaoming::V1_0::IXiaoming follow.
12 Return<void> Xiaoming::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
13 // TODO implement
14 char buf[100];
15 ::memset(buf, 0x00, 100);
16 ::snprintf(buf, 100, "Hello World, %s", name.c_str());
17 hidl_string result(buf);
18
19 _hidl_cb(result);
20
21 return Void();
22 }
23
24
25 // Methods from ::android::hidl::base::V1_0::IBase follow.
26
27 IXiaoming* HIDL_FETCH_IXiaoming(const char* /* name */) {
28 return new Xiaoming();
29 }
30 //
31 } // namespace implementation
32 } // namespace V1_0
33 } // namespace xiaoming
34 } // namespace hardware
35 } // namespace android
因为我们之前的update已经帮我们创建好了Android.bp文件了,我们就直接执行就行了,你们可以看一下那个Android.bp文件,其实就是相当于makefile.我们用mmm来编译就行:
mmm hardware/interfaces/xiaoming/1.0/default/
1
然后你就会看到让人惊喜的一幕了:
这就算是编译好了,生成的库在你的路径下能够找到,像上面的图的路径就是,你的源码根目录文件下:
out/target/product/kona/vendor/lib/hw/
可以找到.
第四步:binder server端进程代码编写
要编译生成android.hardware.naruto@1.0-service模块需要依赖我们之前touch的那两个文件,首先我们修改android.hardware.xiaoming@1.0-service.rc 文件,如下:
执行
sudo vim android.hardware.xiaoming@1.0-service.rc
然后输入:
1 service xiaoming_hal_service /vendor/bin/hw/android.hardware.xiaoming@1.0-service
2 class hal
3 user system
4 group system
保存退出后再执行:
sudo vim service.cpp
添加:
1 #define LOG_TAG "android.hardware.xiaoming@1.0-service"
2
3 # include <android/hardware/xiaoming/1.0/IXiaoming.h>
4
5 # include <hidl/LegacySupport.h>
6
7 using android::hardware::xiaoming::V1_0::IXiaoming;
8 using android::hardware::defaultPassthroughServiceImplementation;
9
10 int main() {
11 return defaultPassthroughServiceImplementation<IXiaoming>();
12 }
13
保存推出后让我们修改Android.bp文件,添加:
先执行:
sudo vim Android.bp
然后添加:
29 cc_binary {
30 name: "android.hardware.xiaoming@1.0-service",
31 defaults: ["hidl_defaults"],
32 proprietary: true,
33 relative_install_path: "hw",
34 srcs: ["service.cpp"],
35 init_rc: ["android.hardware.xiaoming@1.0-service.rc"],
36 shared_libs: [
37 "libhidlbase",
38 "libhidltransport",
39 "libutils",
40 "liblog",
41 "android.hardware.xiaoming@1.0",
42 ],
43 }
保存退出后执行:
mmm hardware/interfaces/xiaoming/1.0/default/
就会惊喜地发现:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200426105609122.png
这样子service就已经编译成功了,是不是转到有点头晕了?
让我们连理清一下我们刚刚生成的文件:
android.hardware.naruto@1.0-impl.so: Naruto模块实现端的代码编译生成,binder server端
android.hardware.naruto@1.0.so: Naruto模块调用端的代码,binder client端
naruto_hal_service: 通过直通式注册binder service,暴露接口给client调用
android.hardware.naruto@1.0-service.rc: Android native 进程入口
这里引用一张官方的引用流程图吧:
第五步:HIDL测试代码的编写
这里我得多说一下了,我做的时候按照教程走把文件目录放在连xiaoming里面编译,发现了两个问题,第一个就是如果放在default里面,是编译不到的,就是就算你程序是错误的,也是会编译成功的,然后我就试着拉出来1.0文件的目录下,然后就悲剧了,一编译就死机,是电脑卡死的那种,因为我是菜鸡,然后我以为自己哪里步骤错误了,或者是使用的线程太多了,因为我的电脑编译本来就会很卡,所以我也没在意,一直等,等了两个小时,还不行,强制重启,然后觉得是偶然事件,再编译,又死机,又强制重启,然后重构,再次死机,然后找方法,未果,然后理解流程,然后想它不就是要一个设备能执行的可执行文件吗?那我就在其他目录编译试试,居然成功了,当我以为我就是可以了,然而你是想不到下面还会发生什么的,操作失误和bug你永远不知道哪一个先来,故事待续…
首先,在源码根目录的external的文件夹下面建立一个test_xiaoming文件夹(其实放在哪里都一样的),然后建立client.cpp文件,文件中添加代码:
1 #include <android/hardware/xiaoming/1.0/IXiaoming.h>
2
3 # include <hidl/Status.h>
4
5 # include <hidl/LegacySupport.h>
6
7 # include <utils/misc.h>
8
9 # include <hidl/HidlSupport.h>
10
11 # include <stdio.h>
12
13 using android::hardware::xiaoming::V1_0::IXiaoming;
14 using android::sp;
15 using android::hardware::hidl_string;
16
17 int main()
18 {
19 // int ret;
20
21 android::sp<IXiaoming> service = IXiaoming::getService();
22 if(service == nullptr) {
23 printf("Failed to get service\n");
24 return -1;
25 }
26
27 service->helloWorld("xiaoming", [&](hidl_string result) {
28 printf("%s\n", result.c_str());
29 });
30
31 return 0;
32 }
然后,编写Android.mk文件,如下:
1 LOCAL_PATH := $(call my-dir)
2
3 include $(CLEAR_VARS)
4 LOCAL_PROPRIETARY_MODULE := true
5 LOCAL_MODULE := xiaoming_test
6 LOCAL_SRC_FILES := \
7 client.cpp \
8
9 LOCAL_SHARED_LIBRARIES := \
10 liblog \
11 libhidlbase \
12 libutils \
13 android.hardware.xiaoming@1.0 \
14
15 include $(BUILD_EXECUTABLE)
然后编译:
mmm external/test_xiaoming/
之后同样的,你也会欣喜的发现,你距离成功已经很近了:
在你的源码根目录下的/out/target/product/kona/vendor/bin文件夹下发现了naruto_test的身影.
第六步:将所需文件push上去设备对应的分区
如果我写到这里就不写了,估计你们是会崩溃的,我在找资料的时候还真的有,什么叫对应分区啊,我是菜鸟我不懂,可能你们懂吧.
然后既然都写到这里了,我就一次性写完吧,谁都想不到菜鸡的我,这个东东就搞了两天,还不断死机,系统都刷了五六次,因为我的设备是手机,主要我还不会刷手机,还要找别人刷,然后差点就怀疑人生了.所以才下定决心写这一个的.
在对应文件的文件夹下push,路劲我就不说了,因为你们编译完成后是会有的,每个人的都不一定一样,我说文件吧.
1 adb push android.hardware.xiaoming@1.0-service /system/vendor/bin/hw
2 adb push android.hardware.xiaoming@1.0.so /system/vendor/lib64
3 adb push android.hardware.xiaoming@1.0-impl.so /system/vendor/lib64/hw
4 adb push xiaoming_test /system/vendor/bin/hw
注意:有些人说也可以放在vendor里面的,问题也不会很大,但是最好放同一个文件夹里面,还有就是记得.-impl.so文件要放在hw里面,但是如果你将.so文件放进去是找不到的,找不到的时候你可以看看输出什么错误信息,如果没有错误信息可以用
adb logcat | grep xiaoming
看看,这是一个抓log的指令
最后一步,就是修改manifest.xml文件了,在里面添加xiaoming接口,注意,这个东西很多人说找不到的,可以在system文件夹下用指令:
find . -name manifest
试一下,一般是会能找到的,然后用指令
adb pull /system/vendor/etc/vintf/manifest.xml ./
/system/vendor/etc/vintf/manifest.xml这个路径是你自己的manifest.xml的文件路径,然后在里面添加代码:(一般你看看人家怎么添加的就行了)
<hal format="hidl">
<name>android.hardware.xiaoming</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IXiaoming</name>
<instance>default</instance>
</interface>
</hal>
然后再push回去:
push manifest.xml /system/etc/vintf
然后重启,重启后再在对应目录下运行:
./android.hardware.xiaoming@1.0-service
启动服务器,然后再在对应的目录下启动客户端就行了:
./xiaoming_test
最后成功是这个样子的:
原文出自:原文链接
哈哈,这里已经是文章的结尾了,我相信很少人会看到这里的,那我就自己哔哔几句吧,应该有人会好奇我怎么会死机,系统都能够崩溃的,其实就是看了教程,有人说将manifest.xml文件放在vendor文件下面或者system下就可以成功了,因为当时一直获取服务器失败,然后文章说和你有没有添加接口有关,所以就那么干了,最后还是逐渐测试才验证到是那个问题的,不过巧合下也让我懂得了接口添加后需要重启就可以找到服务了,但是启动服务的时候也是遇到了很多问题网上的大部分教材都是编辑系统文件的,然后烧写镜像的(可能也与我不会搜有关系),然后我的代码本来就编译比较难成功的,哈哈,我就放弃了这种想法,就算成功了,我也找不到那个system,img文件,因为goole给改名字了,改成什么名字我也不知道了.因为我很菜,哈哈,希望能够给大家一点点帮助