注:在没有特殊说明下,所有操作都在aosp目录下进行。
1.编译(基于ubuntu16.04)
1.1先安装repo工具(参考https://mirrors.tuna.tsinghua.edu.cn/help/git-repo/)
1.2代码下载
到内网10.19.118.212的/home/neusoft/android_source/zhangshuang文件夹下(用户名:neusoft,密码:root)用smb把aosp_9_back.tar.gz拷贝到任意目录,然后解压
或者
$ repo init -u https://android.googlesource.com/platform/manifest -b android-9.0.0_r39 --depth=1
$ repo sync
1.3编译
$ source build/envsetup.sh
// 因为我们要实验car的版本
$ lunch 10
$ make -j8
1.4启动模拟器
编译成功之后,输入命令emulator可以启动模拟器(模拟器更多指令参数参照emulator -help)
2.HAL服务端开发
2.1.编写hal文件
在AOSP代码的目录 hardware/interfaces/中新建test/1.0/,在此目录中新建 ITest.hal,内容:
package android.hardware.test@1.0;
interface ITest{
helloWorld(string name) generates (string result);
};
2.2.使用hidl-gen生成对应的c++文件
2.2.1编译hidl-gen工具
make hidl-gen
2.2.2设置临时变量
PACKAGE=android.hardware.test@1.0
LOC=hardware/interfaces/test/1.0/default
2.2.3生成c++文件
(在aosp根目录下执行,source完之后执行croot可以回到aosp根目录)
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
2.2.4生成Android.bp文件
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
2.2.5生成1.0目录下的Android.bp
执行./hardware/interfaces/update-makefiles.sh
2.3实现c++文件
2.3.1Test.h文件实现passthrough模式
#ifndef ANDROID_HARDWARE_TEST_V1_0_TEST_H
#define ANDROID_HARDWARE_TEST_V1_0_TEST_H
#include <android/hardware/test/1.0/ITest.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
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::hardware::test::V1_0::ITest follow.
Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) 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 hardware
} // namespace android
#endif // ANDROID_HARDWARE_TEST_V1_0_TEST_H
2.3.2Test.cpp实现
#include "Test.h"
namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {
// Methods from ::android::hardware::test::V1_0::ITest follow.
Return<void> Test::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
// TODO implement
// 做了简单实现 start @{
printf("Test helloWorld");
char buf[100];
memset(buf, 0, 100);
snprintf(buf, 100, "Hello World, %s", name.c_str());
hidl_string result(buf);
_hidl_cb(result);
// 做了简单实现 end @}
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 hardware
} // namespace android
2.4添加启动service
在hardware/interfaces/test/1.0/default目录下新建android.hardware.test@1.0-service.rc 启动脚本
service test_hal_service /vendor/bin/hw/android.hardware.test@1.0-service
class hal
user system
group system
2.5新建service.cpp,采用直通式
#define LOG_TAG "android.hardware.test@1.0-service"
#include <android/hardware/test/1.0/ITest.h>
#include <hidl/LegacySupport.h>
using android::hardware::test::V1_0::ITest;
using android::hardware::defaultPassthroughServiceImplementation;;
//passthrough mode
int main() {
return defaultPassthroughServiceImplementation<ITest>();
//passthrough mode
}
2.6修改hardware/interfaces/test/1.0/default目录下的Android.bp
cc_library_shared {
name: "android.hardware.test@1.0-impl",
relative_install_path: "hw",
proprietary: true,
srcs: [
"Test.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"android.hardware.test@1.0",
],
}
cc_binary {
name: "android.hardware.test@1.0-service",
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["service.cpp"],
init_rc: ["android.hardware.test@1.0-service.rc"],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"liblog",
"android.hardware.test@1.0",
],
}
2.7调用update-makefiles.sh更新一下
执行./hardware/interfaces/update-makefiles.sh
2.8.编译
mmm ./hardware/interfaces/test/1.0
3.VNDK相关(https://chendongqi.me/2019/09/01/hidl-binderizing-passthrough/)
build/make/target/product/vndk/28.txt增加一行
build/make/target/product/vndk/current.txt增加一行
4.device部分
为了保证新增的hidl是可以被客户端访问到的,由于此次要使用emulator验证,并且lunch的是aosp_car_x86_64-eng所以在device找到下面目录device/generic/car/common/manifest.xml添加如下内容:
<hal format="hidl">
<name>android.hardware.test</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ITest</name>
<instance>default</instance>
</interface>
</hal>
5.完整编译
在aosp根目录执行make编译出相应的镜像
5.1错误处理
Added VNDK-core: android.hardware.power@1.3.so
error: VNDK library list has been changed.
Changing the VNDK library list is not allowed in API locked branches.
[ 2% 13/554] build out/target/product/g...pp_intermediates/oat/x86_64/package.odex
ninja: build stopped: subcommand failed.
09:47:07 ninja failed with: exit status 1
#### failed to build some targets (14 seconds) ####
将build/make/target/product/vndk/28.txt
build/make/target/product/vndk/current.txt
与out/target/product/generic_x86_64/obj/PACKAGING/vndk_intermediates/libs.txt
文件比较,将libs.txt中的内容同步到28.txt和current.txt文件中。
6.启动服务
6.1启动模拟器
// -writable-system让模拟器可写,-selinux disabled跳过selinux检查
emulator -writable-system -selinux disabled
执行如下命令
// 获取root权限
adb root
// 获取模拟器写权限
adb remount
// 进入模拟器控制台
adb shell
// 启动hal服务
vendor/bin/hw/android.hardware.test@1.0-service &
6.2查看服务是否启动成功
ps -A |grep "test"
7.客户端测试程序
7.1.c++客户端
7.1.1内容编写
在packages/apps目录下新建testApp/native文件夹,创建Android.mk,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE := test
LOCAL_SRC_FILES := \
client.cpp \
LOCAL_SHARED_LIBRARIES := \
liblog \
libhidlbase \
libutils \
android.hardware.test@1.0 \
include $(BUILD_EXECUTABLE)
创建client.cpp内容如下:
# include <android/hardware/test/1.0/ITest.h>
# include <hidl/Status.h>
# include <hidl/LegacySupport.h>
# include <utils/misc.h>
# include <hidl/HidlSupport.h>
# include <stdio.h>
using android::hardware::test::V1_0::ITest;
using android::sp;
using android::hardware::hidl_string;
int main()
{
fprintf(stderr,"%s\n" , "start");
android::sp<ITest> service = ITest::getService();
printf("%s\n", "service");
if(service == nullptr) {
printf("Failed to get service\n");
return -1;
}
service->helloWorld("test", [&](hidl_string result) {
printf("%s\n", result.c_str());
});
printf("%s\n", "end");
return 0;
}
7.1.2.编译客户端
mmm packages/apps/testApp/native/,编译成功之后
7.1.3.把可执行文件push到模拟器中
adb push out/target/product/generic_x86/vendor/bin/test /vendor/bin/
7.1.4.在模拟器控制台中验证是否成功
8.在App中调用hal服务
在编译hal服务端的时候,自动编译出来的java端支持的客户端,编译的结果在(可以通过反编译来查看里面的具体内容)
打包之后再模拟器的路径
所以我们的app只需要引入包即可调用hal的客户端
8.1编写HAL客户端
在packages/apps/testApp中新建如下目录(完整程序在git@github.com:nicholaszhou/HalClientTest.git)
编译客户端程序
mmm packages/apps/testApp
编译成功之后,在会生成客户端的apk程序
把apk安装到模拟器中
adb install -r out/target/product/generic_x86/system/app/TestApp/TestApp.apk
点击运行程序