Android P HAL层添加HIDL实例
本文是参照 https://www.jianshu.com/p/b80865c61d8e 教程介绍实现,原理请参考原作者。
本文将介绍如何在P OS上添加HIDL详细实现过程,简单增加seLinux策略使得可以在system_service调用测试,并用模拟器emulator验证。
调用过程为 APP->TestManager->TestService->ITest.hal
文章目录
实现过程
一 、hardware部分
1.1 编写 .hal
.hal的语言格式是C++和Java的结合体。
在 AOSP代码目录 hardware/interfaces/test/1.0/
新建 types.hal (非必要,用于定义结构体,复杂变量可在此定义)
//types.hal
package android.hardware.test@1.0;
struct TestID{
int32_t id;
string name;
};
struct TestEvent{
int32_t what;
string msg;
};
新建ITestCallback.hal (非必要,用于回调使用)
//ITestCallback.hal
package android.hardware.test@1.0;
interface ITestCallback {
oneway onTestEvent(TestEvent event);
};
新建 ITest.hal (主接口)
//ITest.hal
package android.hardware.test@1.0;
interface ITest {
init(TestID id);
//无返回值
helloWorld(string name) generates (string result);
//变量类型string 不是String
setCallback(ITestCallback callback) generates (bool res);
//变量类型bool 不是boolean
release();
};
1.2 使用hidl-gen生成变量
使用hidl-gen的前提是AOSP全编通过,如果之前全编通过可不用再次全编
source ./build/envsetup.sh
lunch aosp_car_x86_64-eng
make -j4
make hidl-gen -j4
设置临时变量
PACKAGE=android.hardware.test@1.0
LOC=hardware/interfaces/test/1.0/default
使用hidl-gen生成default目录 里的C++文件
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
使用hidl-gen生成default目录 里的Android.bp文件
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
使用update-makefiles.sh生成1.0目录下的Android.bp
./hardware/interfaces/update-makefiles.sh
在default目录创建
此时的目录结构为
├── 1.0
│ ├── default
│ │ ├── Android.bp
│ │ ├── Test.cpp
│ │ ├── Test.h
│ │ ├── TestCallback.cpp
│ │ └── TestCallback.h
│ ├── Android.bp
│ ├── ITest.hal
│ ├── ITestCallback.hal
│ └── types.hal
TestCallback.cpp和 TestCallback.h没用删掉,并修改default里的Android.bp 删掉TestCallback.cpp
1.3 实现.cpp
Test.h (由hidl-gen工具生成)
line 35 注释打开就是使用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>
#include <utils/Thread.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 , public Thread{
// Methods from ::android::hardware::test::V1_0::ITest follow.
Return<void> init(const ::android::hardware::test::V1_0::TestID& id) override;
Return<void> helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) override;
Return<bool> setCallback(const sp<::android::hardware::test::V1_0::ITestCallback>& callback) override;
Return<void> release() override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
virtual bool threadLoop();
};
// 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
Test.cpp (由hidl-gen工具生成)
简单实现各个方法
#define LOG_TAG "Test_cpp"
#include "Test.h"
#include <log/log.h>
namespace android {
namespace hardware {
namespace test {
namespace V1_0 {
namespace implementation {
pthread_t pthread;
sp<ITestCallback> mCallback = nullptr;
std::string mName;
int32_t mID;
bool mExit;
// Methods from ::android::hardware::test::V1_0::ITest follow.
Return<void> Test::init(const ::android::hardware::test::V1_0::TestID& id) {
mExit = false;
mName = id.name;
mID = id.id;
ALOGD("init:");
run("test_thread");
return Void();
}
Return<void> Test::helloWorld(const hidl_string& name, helloWorld_cb _hidl_cb) {
ALOGD("helloWorld:");
char buf[100];
::memset(buf,0x00,100);
::snprintf(buf,100,"Hello World,%s",name.c_str());
hidl_string result(buf);
_hidl_cb(result);
return Void();
}
Return<bool> Test::setCallback(const sp<::android::hardware::test::V1_0::ITestCallback>& callback) {
mCallback = callback;
bool res = false;
if(mCallback != nullptr) {
ALOGD("setCallback: done");
res = true;
}
return res;
}
Return<void> Test::release() {
mExit = true;
ALOGD("release:");
return Void();
}
bool Test::threadLoop(){
static int32_t count = 0;
TestEvent event;
while(!mExit) {
::sleep(1);
event.msg = mName;
event.what = count ++;
if(mCallback != nullptr) {
mCallback->onTestEvent(event);
}
}
ALOGD("threadLoop: exit");
return false;
}
// 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
添加启动service
新建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
新建service.cpp 这里使用绑定式 直通式为注释部分
#define LOG_TAG "android.hardware.test@1.0-service"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <android/hardware/test/1.0/ITest.h>
#include <hidl/LegacySupport.h>
#include "Test.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::test::V1_0::implementation::Test;
//using android::hardware::defaultPassthroughServiceImplementation;
//passthrough mode
int main() {
configureRpcThreadpool(4, true);
Test test;
auto status = test.registerAsService();
CHECK_EQ(status, android::OK) << "Failed to register test HAL implementation";
joinRpcThreadpool();
return 0; // joinRpcThreadpool shouldn't exit
// return defaultPassthroughServiceImplementation<ITest>();
//passthrough mode
}
修改Android.bp
cc_binary {
name: "android.hardware.test@1.0-service",
relative_install_path: "hw",
defaults: ["hidl_defaults"],
proprietary: true,
init_rc: ["android.hardware.test@1.0-service.rc"],
srcs: [
"Test.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"liblog",
"libdl",
"libutils",
"libhardware",
"libhidlbase",
"libhidltransport",
"android.hardware.test@1.0",
],
}
调用 update-makefiles.sh更新一下
当前目录结构为
├── 1.0
│ ├── default
│ │ ├── Android.bp
│ │ ├── Test.cpp
│ │ ├── Test.h
│ │ ├── android.hardware.test@1.0-service.rc
│ │ └── service.cpp
│ ├── Android.bp
│ ├── ITest.hal
│ ├── ITestCallback.hal
│ └── types.hal
单编试一下 ,出错请检查代码请参考附录解决办法。
mmm ./hardware/interfaces/test/1.0
1.4 VNDK相关
在目录aosp\build\make\target\product\vndk 里
28.txt 和 current.txt 按照字母顺序新增
VNDK-core: android.hardware.test@1.0.so
二、device部分
由于此次要使用emulator验证,并且lunch的是aosp_car_x86_64-eng
所以在device找到下面目录aosp\device\generic\car\common\manifest.xml
其他device要在对应的目录找到manifest
在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>
在car.mk添加 启动 test service
# Auto modules
PRODUCT_PACKAGES += \
……
android.hardware.test@1.0-service
三、SELinux部分——hal service
根据其他博主的文章搜集了一些SELinux的知识点进行补充:
对应sepolicy, Google 也设定了不同的存放目录, 以便进行分离, 以Google 默认的sepolicy 为例. /system/sepolicy
public: android 和 vendor 共享的sepolicy 定义, 通常情况下, 意味着vendor 开发者可能为此新增一些权限. 一般system/vendor 共用的一些类型和属性的定义, neverallow 限制等会存放于此.
private: 通常意义上的仅限于system image 内部的使用, 不对vendor 开放. 这个只会编译到system image 中.
vendor: 它仅仅能引用public 目录下的相关定义, 这个只会编译到vendor image 中. 但它依旧可以对system image 里面的module 设定sepolicy(对应module 需要在public 下进行声明); 在很大程度上绕过了Google GTS 约束测试.
mapping: 为兼容老版本的sepolicy 而导入, 只有在system image version > vendor version 的时候, 才可能被用到. 即包括两方面, 新版本增加的type , 新版本移除的type, 以及老版本public, 新版本private 等变化的设定, 以兼容老版本.
9.0上Android 安全策略再次加强,hal service需要修改selinux配置
lunch为 aosp_car_x86_64-eng 对应的car device目录下没有BoardConfig.mk,也没有对应的sepolicy
所以只能修改系统的sepolicy
目录为aosp\system\sepolicy
该目录下有vendor public private(注意public 下的修改同样也要修改到prebuilts\api\28.0 下的对应文件,否则编译会报错) 位置找不到参考audiocontrol的位置 或者比较熟悉的hal模块
3.1 vendor 目录
file_contexts 添加
/(vendor|system/vendor)/bin/hw/android\.hardware\.test@1\.0-service u:object_r:hal_test_default_exec:s0
#file_contexts文件保存系统中所有文件的安全上下文定义,每行前半部分是文件的路径,后面是它的安全上下文的定义(hal_test_default_exec)
新建 hal_test_default.te
在TE中,所有的东西都被抽象成类型。进程,抽象成类型;资源,抽象成类型。属性,是类型的集合。所以,TE规则中的最小单位就是类型。
#定义一个 名字为 hal_test_default 的type
#TYPE是定义主体和客体所属的类型,对于进程而言,它的类型也称为domian。
#通常主体的type具有domian属性,因此,我们也把主体的type称为domain,将domain设置为hal_test_default的属性,表明zygote是用来描述进程的安全上下文的。
# Set a new domain called hal_test_default
type hal_test_default, domain;
# Set your domain as server domain of hal_xxx in which define by AOSP already
hal_server_domain(hal_test_default, hal_test)
# Set your exec file type
type hal_test_default_exec, exec_type, vendor_file_type, file_type;
# Setup for domain transition
init_daemon_domain(hal_test_default)
3.2 public 目录
attributes 添加
hal_attribute(test);
hwservice.te 添加
type hal_test_hwservice, hwservice_manager_type;
新建 hal_test.te
# HwBinder IPC from client to server, and callbacks
binder_call(hal_test_client, hal_test_server)
binder_call(hal_test_server, hal_test_client)
add_hwservice(hal_test_server, hal_test_hwservice)
allow hal_test_client hal_test_hwservice:hwservice_manager find;
将以上修改同步到aosp\system\sepolicy\prebuilts\api\28.0\public
3.3 private 目录
hwservice_contexts 添加
android.hardware.test::ITest u:object_r:hal_test_hwservice:s0
private/compat/26.0/26.0.ignore.cil 添加
hal_test_hwservice
private/compat/27.0