Android P HAL层添加HIDL实例(详细实现步骤)

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

[外链图片转存失败(img-pGZeVrJ7-1563157041998)(C:\Users\GW00175635\AppData\Roaming\Typora\typora-user-images\1562749332399.png)]

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

评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值