news 2026/5/1 11:08:19

自定义 Android 系统服务与 HAL 交互全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自定义 Android 系统服务与 HAL 交互全流程指南

一、整体架构:两层服务,两套查找机制

你的服务分为两个层次,分别用不同的“服务管理器”管理:

  1. 系统服务层TestService

    • 运行在system_server进程中

    • 通过ServiceManagerservicemanager)发布,名为"testtld"

    • 上层 App 通过ServiceManager.getService("testtld")获取

    • 对应接口:ITestHalManager

  2. HAL 层(C++ 编译的独立进程)

    • 运行在独立进程android.hardware.testtld-service

    • 通过hwservicemanager(或直接注册到servicemanager,当前暂时如此)发布

    • 描述符为"android.hardware.testtld.IHelloTest",实例名为"default"

    • 系统服务通过IHelloTest.DESCRIPTOR + "/default"找到它

    • 对应接口:IHelloTest(由 AIDL 生成)

交互链路:
应用层 →ServiceManager.getService("testtld")ITestHalManagerTestServiceIHelloTest.Stub.asInterface()→ HAL 服务

二、代码组件一览

1. AIDL 接口定义

HAL 接口:hardware/interfaces/testtld/aidl/android/hardware/testtld/IHelloTest.aidl

package android.hardware.testtld; @VintfStability interface IHelloTest { int getTestOne(in int event, in String name); void test_write(String str); String test_read(); }

由此生成 Java 绑定android.hardware.testtld-V1-java

系统内部接口:frameworks/base/core/java/android/hardware/testtld/ITestHalManager.aidl

package android.hardware.testtld; /** * {@hide} */ interface ITestHalManager { void testhal_write(String str); String testhal_read(); }

由此生成ITestHalManager.Stub,供TestService发布。

2. Java 系统服务TestService.java

路径:frameworks/base/services/core/java/com/android/server/testtld/TestService.java

核心代码:

import android.hardware.testtld.IHelloTest; import android.hardware.testtld.ITestHalManager; public class TestService extends SystemService { private IHelloTest mVintfTestHal = null; private ITestHalManager mTestHalManager = null; private final class TestHalManagerServiceImpl extends ITestHalManager.Stub { @Override public void testhal_write(String str) throws RemoteException { if (mVintfTestHal != null) { mVintfTestHal.test_write(str); // 调用 HAL } } @Override public String testhal_read() throws RemoteException { if (mVintfTestHal != null) { return mVintfTestHal.test_read(); } return ""; } } public TestService(Context context) { super(context); IBinder binder = Binder.allowBlocking( ServiceManager.waitForDeclaredService(IHelloTest.DESCRIPTOR + "/default")); if (binder != null) { mVintfTestHal = IHelloTest.Stub.asInterface(binder); } mTestHalManager = new TestHalManagerServiceImpl(); } @Override public void onStart() { publishBinderService("testtld", (IBinder) mTestHalManager); } }

关键字符串映射:
IHelloTest.DESCRIPTOR="android.hardware.testtld.IHelloTest"
HAL 服务全名 ="android.hardware.testtld.IHelloTest/default"
系统服务发布名 ="testtld"


3. C++ HAL 服务实现

路径:hardware/interfaces/testtld/service.cpp(示例)

using namespace aidl::android::hardware::testtld; ndk::ScopedAStatus HelloTest::test_write(const std::string& str) { ALOGD("test_write: %s", str.c_str()); return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus HelloTest::test_read(std::string* _aidl_return) { *_aidl_return = "hello from HAL"; return ndk::ScopedAStatus::ok(); } // 注册服务 int main() { ... std::shared_ptr<HelloTest> service = ndk::SharedRefBase::make<HelloTest>(); binder_status_t status = AServiceManager_addService(service->asBinder().get(), "android.hardware.testtld.IHelloTest/default"); ... }

三、AIDL 接口冻结与版本控制(重点概念)

为什么需要冻结?

  • 保证硬件接口的兼容性,防止签名被意外修改。

  • 冻结后,系统会生成哈希记录,如果 AIDL 改动,编译时会报错强制升版本。

冻结的时机

修改接口之后,确认内容不再变化时执行freeze-api
正确顺序:先改.aidl→ 再冻结 → 最后编译绑定

兼容 vs 不兼容修改

改动类型是否需要升级版本举例
新增方法不需要(兼容)增加test_write,保留getTestOne
删除方法、改方法名、改参数必须升版本(例如 V2)删除getTestOne或修改其参数

如何冻结(兼容性修改)

m android.hardware.testtld-freeze-api # 更新 V1 冻结记录 m android.hardware.testtld-V1-java # 重新编译 java 绑定

Android.bpversions_with_info无需改动,保持"1"

如何升级版本(不兼容修改)

  1. 修改Android.bp,新增 V2 版本信息(保留 V1)

  2. 修改.aidl

  3. m android.hardware.testtld-freeze-api

  4. 在依赖处改用android.hardware.testtld-V2-java

四、SELinux 配置(设备专用目录)

所有规则文件放在device/<vendor>/<board>/sepolicy/下,并在BoardConfig.mk中添加:

BOARD_SEPOLICY_DIRS += device/<vendor>/<board>/sepolicy

需要创建/修改的文件

1.service.te— 定义系统服务类型
type testtld_service, service_manager_type;
2.service_contexts— 系统服务名称与安全类型映射
testtld u:object_r:testtld_service:s0

安全上下文格式:用户:角色:类型:级别

  • u= SELinux 用户(固定)

  • object_r= 角色(被动实体,固定)

  • testtld_service= 自定义类型(需提前在service.te中定义)

  • s0= 安全级别(最低敏感度,固定)

3.hwservice_contexts— HAL 服务映射(当前 HAL 直接注册在servicemanager时可省略,规范做法应通过hwservicemanager
android.hardware.testtld.IHelloTest::default u:object_r:hal_testtld_default:s0
4.hal_hellotest.te— 允许 HAL 进程注册服务
allow hal_hellotest default_android_service:service_manager add;

5.system_server.te— 允许 system_server 注册和查找

allow system_server default_android_service:service_manager find; allow system_server testtld_service:service_manager add;
6.priv_app.te— 允许 Launcher 查找和调用
allow priv_app testtld_service:service_manager find; allow priv_app testtld_service:binder { call transfer };

注意:Launcher 运行在priv_app域(因为装在/system/priv-app),不是system_app。规则中的源域必须精确匹配进程的实际域。

调试查看拒绝

dmesg | grep avc

五、SELinux 域(Domain)盲区解析

  • 域 = 进程的安全标签中的“类型”部分,类似“工作制服”。

  • Android 根据应用安装位置自动分配域:

    • /system/priv-app/priv_app(黑色制服,高特权,如 Launcher、Settings)

    • /system/app/system_app(蓝色制服,普通系统应用)

    • 系统服务进程 →system_server(白色制服)

  • 权限规则必须源域完全匹配才生效。给system_app的权限不会作用于priv_app

  • 如何确认进程域:
    ps -Z | grep <进程名>或查看 SELinux 拒绝日志中的scontext=u:r:XXX:s0

六、Launcher 调用示例

Launcher.java已有的onCreate中添加:

import android.os.IBinder; import android.os.ServiceManager; import android.os.RemoteException; import android.hardware.testtld.ITestHalManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 原有代码 ... IBinder binder = ServiceManager.getService("testtld"); if (binder != null) { ITestHalManager manager = ITestHalManager.Stub.asInterface(binder); try { manager.testhal_write("nihao"); } catch (RemoteException e) { Log.e("Launcher", "write failed", e); } } }

七、调试与排错

查看 SELinux 拒绝日志

在设备终端(adb shellsu获取 root):

logcat -c # 清空缓冲区 # 触发相关操作 logcat -d | grep "avc: denied"

或过滤特定服务:

logcat -d | grep -E "testtld|avc.*denied"

根据拒绝日志补写规则

例如日志:

avc: denied { find } for pid=1134 name=testtld scontext=u:r:priv_app:s0 tcontext=u:object_r:testtld_service:s0 tclass=service_manager permissive=1

需要添加:

allow priv_app testtld_service:service_manager find;

切换 SELinux 模式

  • 查看当前模式:getenforce

  • 设为宽容模式(不阻断):setenforce 0

  • 设为强制模式(阻断并记录):setenforce 1

八、快速检查清单

  • AIDL 文件定义清晰,方法与 Java 调用一致

  • HALaidl_interfaceAndroid.bp中 Java 后端已启用enabled: true

  • services.coreAndroid.bp中已依赖android.hardware.testtld-V1-java

  • 系统服务publishBinderService的名称与service_contexts中的名称完全一致

  • HAL 服务描述符和实例名与 Java 代码中waitForDeclaredService的参数完全一致

  • 设备 sepolicy 目录已正确配置并包含在BoardConfig.mk

  • 所有avc: denied日志已通过添加明确规则解决

  • Launcher 所用域(priv_app)的规则已单独添加

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 11:06:28

LinkSwift:一站式多网盘直链下载助手终极指南

LinkSwift&#xff1a;一站式多网盘直链下载助手终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 / 迅…

作者头像 李华
网站建设 2026/5/1 11:06:23

告别网盘下载烦恼:LinkSwift八大网盘直链下载助手终极指南

告别网盘下载烦恼&#xff1a;LinkSwift八大网盘直链下载助手终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …

作者头像 李华
网站建设 2026/5/1 10:56:26

告别Token焦虑:用tiktoken精准计算你的GPT API调用成本(Python实战)

告别Token焦虑&#xff1a;用tiktoken精准计算你的GPT API调用成本&#xff08;Python实战&#xff09; 在AI应用开发中&#xff0c;OpenAI的GPT系列模型已经成为许多项目的核心引擎。但每次API调用背后的token计数&#xff0c;往往让开发者们感到焦虑——费用会不会超出预算&a…

作者头像 李华
网站建设 2026/5/1 10:55:22

状态空间模型与门控线性注意力架构解析

1. 架构设计背景与核心概念解析 在自然语言处理领域&#xff0c;序列建模架构的创新一直是推动性能突破的关键。近年来&#xff0c;状态空间模型(State Space Models, SSMs)和门控线性注意力(Gated Linear Attention, GLA)两类架构因其独特的优势受到广泛关注。SSM通过结构化状…

作者头像 李华
网站建设 2026/5/1 10:54:24

Azure部署私有AI助手:OpenClaw自动化部署与安全架构解析

1. 项目概述&#xff1a;在Azure上部署你的专属AI助手 如果你和我一样&#xff0c;对把个人数据交给第三方AI服务商总有些顾虑&#xff0c;同时又希望拥有一个能帮你处理真实任务——比如浏览网页、执行命令、管理文件——的智能助手&#xff0c;那么自己动手搭建一个私有化的…

作者头像 李华