1. 课程导入
Android 系统从 Android 8.0(Treble 项目)开始,对系统架构进行了彻底的分层重构,将原本与 Framework 紧耦合的硬件抽象层(HAL)拆分为独立的 HAL Service 进程,通过 HIDL/Binder 与 Framework 通信。这一变化让 HAL 从"库"变成了"服务",也让 HAL 开发从"改 C 代码"变成了"写一个可独立运行、可调试、可升级的系统服务"。本课程的目标,就是带你从零掌握 Android HAL Service 的开发与调试全流程。
一、学习目标:学完你能做什么
本课程不是泛泛介绍 HAL 概念,而是以"能独立交付一个可用的 HAL Service"为最终验收标准。具体学习目标如下:
- 理解 Treble 架构下 HAL 的分层模型,能说清 Framework、HAL Service、Kernel Driver 三者的边界与通信方式。
- 掌握 HIDL 与 AIDL 两种 HAL 接口定义语言,能根据 Android 版本选择正确的接口类型并编写
.hal/.aidl文件。 - 能独立完成一个 HAL Service 的目录结构搭建、接口实现、编译配置(Android.bp)与开机自启动(init.rc)。
- 掌握 HAL 调试的核心手段:logcat、dumpsys、lshal、Binder 调用跟踪、SELinux 权限排障。
- 能定位并解决 HAL 开发中最常见的四类问题:服务起不来、接口找不到、权限被拒、数据不通。
二、核心概念:先建立正确的"心智模型"
在动手之前,必须先厘清几个容易混淆的核心概念,否则后续调试会处处踩坑。
HAL Service 的本质是一个 Binder 服务进程。它由 init 进程根据 .rc 文件拉起,注册到 ServiceManager,Framework 通过 Binder 代理调用它的接口。它和普通 App 进程最大的区别是:运行在 native 层、以 C++ 为主、受 SELinux 严格约束、随系统启动。
HIDL 与 AIDL 是两代接口技术。Android 8.0~11 主要使用 HIDL(hardware/interfaces/ 目录),Android 11 之后 Google 主推 AIDL for HAL,Android 13 起新 HAL 基本都用 AIDL。两者都支持 Binder 化通信,但语法、版本管理、passthrough 模式差异明显。
Passthrough 与 Binderized 是两种运行模式。Passthrough 模式下 HAL 以库形式被加载进调用进程,主要用于兼容旧 HAL;Binderized 模式才是 Treble 的目标形态,HAL 独立成进程。理解这一点,是看懂 lshal 输出的前提。
三、整体知识框架:一张图看清全貌
下图给出了本课程的知识全景。左侧是 HAL Service 从接口定义到运行时的完整链路,右侧是贯穿始终的调试手段。建议在学习每一章时都回看这张图,明确当前所处的位置。
四、实战路线图:七步走完一个 HAL Service
把上面的知识框架落到操作层面,就是下面这条七步路线。本课程后续章节基本按此顺序展开。
- 环境搭建:下载 AOSP 源码,配置
lunch目标,确认能编译出system.img。 - 接口定义:在
hardware/interfaces/下新建接口目录,编写.hal或.aidl,定义方法、参数、回调。 - 接口实现:继承生成的 Stub 类,实现具体逻辑,处理线程模型与错误码。
- 编译配置:编写
Android.bp,声明cc_binary、依赖库、vintf_fragments。 - 启动配置:编写
init.rc注册服务,配置 SELinuxte文件与file_contexts。 - 启动验证:刷机后通过
lshal确认服务已注册,通过dumpsys查看状态。 - 调试排障:按"起不来→找不到→被拒绝→不通"的顺序逐层排查。
五、典型场景与常见误区
典型场景:假设你要为一个自定义传感器开发 HAL。Framework 层通过 ISensor.getData() 调用,HAL 层需要打开 /dev/sensor0,读取数据并回调给上层。整个链路涉及接口定义、Binder 通信、设备节点访问、SELinux 策略四类工作,任何一类出错都会导致"上层拿不到数据"。
常见误区二:忽略 SELinux。很多"服务起不来"其实是
avc: denied,而不是代码问题。
常见误区三:接口版本管理混乱。HIDL 的
@1.0、@1.1 必须严格对应,随意改接口会导致 VTS 失败。
六、关键概念速查清单
| 概念 | 含义 | 关键点 |
|---|---|---|
| Treble | Android 8.0 引入的分层架构 | HAL 独立成进程,Framework 与 Vendor 解耦 |
| HIDL | HAL 接口定义语言(8.0~11) | 支持 passthrough 与 binderized |
| AIDL for HAL | 新一代 HAL 接口(11+) | 语法更接近 Java AIDL,推荐新项目使用 |
| Binderized | HAL 作为独立 Binder 进程运行 | Treble 目标形态,可独立升级 |
| VINTF | Vendor Interface 清单 | 声明 HAL 版本与可用性,影响匹配 |
| SELinux | 强制访问控制 | HAL 进程的域、设备节点标签必须配对 |
七、一个最小可运行示例的骨架
为了让你对"一个 HAL Service 长什么样"有直观感受,下面给出一个最小服务的目录与关键文件骨架。后续章节会逐行展开。
hardware/interfaces/demo/1.0/
├── Android.bp
├── IDemo.hal
├── default/
│ ├── Android.bp
│ ├── Demo.cpp
│ ├── Demo.h
│ └── demo-service.rc
└── vintf/
└── demo.xml
# demo-service.rc 关键内容
service demo-hal /vendor/bin/hw/android.hardware.demo@1.0-service
class hal
user system
group system
seclabel u:r:hal_demo_default:s0
这段骨架里,IDemo.hal 定义接口,Demo.cpp 实现逻辑,Android.bp 负责编译,demo-service.rc 负责启动,demo.xml 负责 VINTF 声明。五者缺一不可,这也是本课程反复强调的"HAL Service 五件套"。
hello() 方法)跑通全流程,再逐步增加复杂度。跑通一次,胜过读十遍文档。