文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

HAL: 将 HIDL 接口改造为 Stable AIDL

2023-09-03 22:26

关注

目录

1. 定义新的AIDL接口

1.1 编译hidl2aidl工具

1.2 执行转换

1.3 调整编译规则(bp文件)

2. 向vendor镜像添加AIDL接口

2.1 使用update-api freeze-api管理接口版本

2.2 配置 Framework Compatibility Matrix (FCM,兼容性矩阵)

2.3 配置使AIDL编译

2章报错速查

3. 实现service

3.1 编写service代码

3.2 创建service编译规则

3.3 将service添加进系统

3章报错速查

4. 确保service开机启动

4.0 开始配置SEpolicy

4.1 添加新feature目录

4.2 创建 hal_sensorscalibrate_default.te

4.3 创建 file_contexts

4.1 无法启动时的排查方法

5. java层调用service(含sepolicy配置)


欢迎指正交流,谢谢!

1. 定义新的AIDL接口

目标:将旧接口全部转换为新接口

验证目标:肉眼检查所有的接口文件已转换,即可

我们使用AOSP自带的转换工具:hidl2aidl,将旧版hidl接口转换为aidl接口。

1.1 编译hidl2aidl工具

        编译可以在任意位置执行,这里以vendor根目录为例

source /opt/conf/openjdk18.conf
source build/envsetup.sh
lunch 项目名-userdebug
m hidl2aidl

1.2 执行转换

        运行hidl2aidl工具。它会读取我们指定的hidl接口,并生成转换后的aidl。

        在命令里,我们需要指定hidl包的所在位置,不然工具会找不到对应的hidl包。

hidl2aidl -o 输出路径 -r hidl包名:hidl包根目录(即/1.0的上层目录)  hidl包名@要转换的hidl版本

        其中的输出路径,我们创建一个aidl文件夹,此文件夹与hidl接口(1.02.0等文件夹)同级。冒号两侧不能有空格。

        例如:

hidl2aidl -o vendorabcd/hardware/interfaces/sensorscalibrate/aidl/ -r vendorabcd.hardware.sensorscalibrate:vendorabcd/hardware/interfaces/sensorscalibrate vendorabcd.hardware.sensorscalibrate@1.0

1.3 调整编译规则(bp文件)

        首先检查转换生成的文件。转换会生成 .aidl 和 Android.bp 两种文件。

.aidl文件

        检查所在路径,要与包名匹配。例如包名:vendorabcd.hardware.sensorscalibrate,文件路径应为: aidl/vendorabcd/hardware/sensorscalibrate/ISensorsCalibrate.aidl

Android.bp文件

        生成的bp文件需要修改,示例如下:(红色部分为需要修改的部分)

aidl_interface {

    name: "vendorabcd.hardware.sensorscalibrate",

    vendor_available: true, //这里设置为true,因为是vendor目录下的模块

    owner: "vendorabcd", //作为vendor模块,需要设定owner才可以通过编译

    srcs: ["vendorabcd/hardware/sensorscalibrate) {

    return new SensorsCalibrate();

}   //hidlFETCH方法现在不需要,删除

}  // namespace implementation

}  // namespace V1_0

}  // namespace sensorscalibrate

}  // namespace hardware

}  // namespace vendorabcd

}  // namespace aidl

3.2 创建service编译规则

        要配置编译规则,我们在default目录下,继续添加以下三个文件:Android.mk/bp    .rc    .xml  

Android.mk / Android.bp

        指定service的编译规则。

        具体使用mk文件还是bp文件,可以和hidl service保持一致。bp是更现代的方式;但如果要引用mk定义的模块,则也必须使用mk。因此,和hidl版本保持一致是最方便的选择。

        例如,hidl版本此service的Android.mk文件如下。我们直接在其上进行修改,用作aidl版本service的mk文件:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := vendorabcd.hardware.sensorscalibrate@1.0-service

LOCAL_MODULE := vendorabcd.hardware.sensorscalibrate-service

LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_CLASS := EXECUTABLES

LOCAL_MODULE_RELATIVE_PATH := hw

LOCAL_INIT_RC := vendorabcd.hardware.sensorscalibrate@1.0-service.rc

LOCAL_INIT_RC := vendorabcd.hardware.sensorscalibrate-service.rc

//声明此serviceaidl接口的依赖。之后,我们将创建这个文件。

LOCAL_VINTF_FRAGMENTS := vendorabcd.hardware.sensorscalibrate.xml

LOCAL_SRC_FILES := \

    SensorsCalibrate.cpp \

    service.cpp

LOCAL_SHARED_LIBRARIES := \

    libhidlbase \

    libhidltransport \

    libbinder_ndk \ //Stable aidl必需

    libutils \

    libdl \

    liblog \

    libcutils \

    libhardware \

    libbase \

    vendorabcd.hardware.sensorscalibrate@1.0 \

    // 包名-V1-ndk_platform

    vendorabcd.hardware.sensorscalibrate-V1-ndk_platform \

    libhfmanager

include $(BUILD_EXECUTABLE)

.rc

        文件名:vendorabcd.hardware.sensorscalibrate-service.rc

        配置开机启动。

        此rc文件将被init.rc链接。我们可以在此文件中,指定开机时启动aidl service。示例如下:

service vendor.sensorscalibrate-hal /vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service

//service + 注册名(可随意起一个) + 编译后的模块所在路径

    class hal

    user system

    group system

.xml (manifest)

        文件名:vendorabcd.hardware.sensorscalibrate.xml

        我把aidl接口的manifest转移到此处,因为service依赖于aidl。如果未来不需此service,则aidl接口也不编译。这一依赖关系,我们已在Android.mk中的LOCAL_VINTF_FRAGMENTS声明过,此项配置指向的xml文件即为我们现在创建的xml文件。

        把2.3步中的aidl manifest删除,将其中内容转移到default目录下的此文件中。

        内容原样复制即可:

<manifest version="1.0" type="device">

   

        vendorabcd.hardware.sensorscalibrate

        1

       

            ISensorsCalibrate

            default

       

   

尝试编译

        在default目录下运行mm进行编译。(请记得先在vendor根目录下执行source build/envsetup.sh 和 lunch)现在应该能够完成模块编译。

        编译成功后,在out/target/product/>/vendor/bin/hw能看到编译得到的service可执行文件。

3.3 将service添加进系统

        修改device.mk文件,以包含此service。

        我们首先找到hidl版本的编译声明,通常位置为device/vendorabcd/名或chipset>/device.mk

        例如,我找到这样的hidl编译配置:

PRODUCT_PACKAGES += vendorabcd.hardware.sensorscalibrate@1.0-service \

                    vendorabcd.hardware.sensorscalibrate@1.0-service.rc \

                    vendorabcd.hardware.sensorscalibrate@1.0 \

                    vendorabcd.hardware.sensorscalibrate-V1.0-java \

                     vendorabcd-hardware-sensorscalibrate.xml

DEVICE_MANIFEST_FILE += device/vendorabcd/chipset/mgvi/manifest_sensorscalibrate.xml

        升级到aidl以后,只需配置好service,对应的xml即会自动加入编译。

        把以上的内容全部删除。替换为:

PRODUCT_PACKAGES += vendorabcd.hardware.sensorscalibrate-service

        (可选)现在可以全编译一下,确认能够正常完成整个系统的全编译。

3章报错速查

FAILED: ninja: '.xml', needed by 'out_hal/(...)/.xml', missing and no known rule to make it

解释:ninja错误:第2个路径xml中,需求了第1个路径的xml,但是找不到对应的文件

错误原因:可能因为manifest中的旧版本没有删除干净,导致编译器寻找已被删除的xml。

解决方法:检查 DEVICE_MANIFEST_FILE 中旧版的xml配置,并删除干净

ld.lld: error: undefined symbol: >>> the vtable symbol may be undefined because the class is missing its key function

解释:clang错误:没有找到对应的类,因为没有实现对应的虚函数。

错误原因:cpp编写有误,例如实现函数时未声明namespace :SensorsCalibrate::SensorsCal() 错写成 SensorsCal()

解决方法:检查cpp文件并修改

4. 确保service开机启动

目标:开机时service能够自启动

验证目标:开机后,执行adb shell service list,能看到新的service

        本章将要配置SEpolicy以确保service开机启动。SEpolicy是引入了SELinux(kernel)后所需求的一种安全策略。SELinux会默认阻止一些关键操作(例如文件操作,ioctl等),我们需要逐条声明后,才能合法进行这些操作。

4.0 开始配置SEpolicy

        在第3章最后,我们能编译得到一个新的系统版本。但在这个版本中,service不会随开机启动,因为我们还没有配置SEpolicy。一种更具有演示性的做法是,我们收集log中的拒绝信息,再对应配置SEpolicy。然而,由于全编译一次的时间成本过高,在这里,我们先配置完所需的SEpolicy,再检查是否能自动启动。

        需要注意的是,在配置SEpolicy相关文件时,每个文件末尾必须另有一行空白行,否则会在编译时遇到无法预知的错误。具体原因我也不太清楚。

4.1 添加新feature目录

        文件vendor/vendorabcd/security/sepolicy_vendor/features/sepolicy_features_vendor.mk 中定义了vendorabcd的vendor相关sepolicy。我们按格式增加一个feature。

        添加如下一行:

BOARD_SEPOLICY_DIRS += $(LOCAL_PATH)/sensorscalibrate/vendor

        并在此目录下创建/sensorscalibrate/vendor目录。进入这个新创建的目录。

4.2 创建 hal_sensorscalibrate_default.te

        创建一个文件,名为hal_sensorscalibrate_default.te,内容如下:

type hal_sensorscalibrate_default, domain;

type hal_sensorscalibrate_default_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(hal_sensorscalibrate_default)

        其中的init_daemon_domain是一段,可以自动帮助我们完成与init相关的policy声明。这段宏的括号中的输入x应为一个domain(即本文件,在第一行定义),并有名为x_exec的对象被定义为一个executable(在第二行定义)。第一行和第二行满足了init_daemon_domain对输入的需求。

        我们现在还没有把 hal_sensorscalibrate_default_exec 与实际文件相绑定。于是另创建一个文件,名为file_contexts。

4.3 创建 file_contexts

        file_contexts负责声明实际文件为某个SEpolicy中的对象。

        我们将手机中service可执行文件的路径,声明为hal_sensorscalibrate_default_exec

        创建一个文件,名为file_contexts,内容如下:

/(vendor|system/vendor)/bin/hw/vendorabcd\.hardware\.sensorscalibrate-service                   u:object_r:hal_sensorscalibrate_default_exec:s0

4.1 无法启动时的排查方法

1. 确认service本身可正常运行

        我们首先尝试手动启动服务,以收集相关log。

        在adb shell内,切换到su用户。将SEpolicy调整到宽容模式,放行未声明的操作。

su root

setenforce 0

getenforce  #检查是否打开宽容模式(输出Permissive为宽容模式)

        启动服务:

/vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service

        检查服务是否正常启动。不要关闭前一个终端窗口,另开一个窗口,在adb shell中执行

service list | grep sensorscalibrate

        有如下输出,说明启动成功:

159     vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate/default: [vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate]

        如果方括号[ ]内没有内容,可能是未成功打开宽容模式。

2. 检查启动阶段的log

        dmesg是linux提供的内核log工具,与系统启动相关的log在其中有记录。

        打开终端,进入sudo模式,收集本次启动的dmesg:

adb root

adb shell dmesg > dmesg.txt

        如果看到类似于以下的dmesg内容,说明系统启动时,由于SEpolicy阻拦,service启动失败:

[   10.220035] init: init 27: [10038][0]Could not start service 'vendor.sensorscalibrate-hal' as part of class 'hal': File /vendor/bin/hw/vendorabcd.hardware.sensorscalibrate-service(labeled "u:object_r:vendor_file:s0") has incorrect label or no domain transition from u:r:init:s0 to another SELinux domain defined. Have you configured your service correctly?

3 查看系统运行阶段的log

        在宽容模式下,系统不会阻止未声明的操作,但仍记录这些操作的拒绝记录。我们可以通过拒绝记录来添加对应的声明。

        在adb shell中执行

logcat | grep sensorscalibrate

        若看到有如下log,记录了被拒绝的的操作:

11-10 16:29:41.311   633   633 E SELinux : avc:  denied  { find } for pid=3223 uid=2000 name=vendorabcd.hardware.sensorscalibrate.ISensorsCalibrate/default scontext=u:r:shell:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=1

#这个log的意思是我试图从shell启动service但是失败了

        log的格式解释如下:

avc: denied  { 操作权限  }  for pid=7201  comm=“进程名”  scontext=u:r:源类型:s0  tcontext=u:r:目标类型:s0  tclass=访问类别  permissive=0

        修改步骤:

        找相应的“源类型.te ”文件

        按如下格式在该文件中添加:

        allow  源类型 目标类型:访问类别 {权限};

        allow vendorabcd_app hal_sensorscalibrate_default:binder {call};​​​​​​​

5. java层调用service(含sepolicy配置)

        后面写不动了,先到这里吧。

        在msi镜像中,也要定义同样的aidl接口,这样才能进行aidl通信。文件内容使用和vendor中完全相同即可。

推荐阅读:

sepolicy进阶小记 - LibXZR 的小本本 解释了许多关键的sepolicy宏,很有帮助

AIDL for HALs - Code Inside Out 一个AIDL for HAL全流程的文档,比较细

来源地址:https://blog.csdn.net/weixin_60253080/article/details/127810200

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯