Android 系统驱动开发流程详解
Android 驱动开发不同于普通 Linux 驱动,需要打通 Kernel → HAL → JNI → Framework → App 五层调用链。本文以一个 LED 驱动为例走通全流程。
整体架构
code
┌──────────────────────────────────────┐
│ App (Java/Kotlin) │ LedService.turnOn()
│ android.hardware.led.ILedService │
├──────────────────────────────────────┤
│ Framework Service (Java) │ LedManagerService
│ AIDL Binder 跨进程通信 │
├──────────────────────────────────────┤
│ JNI (C++) │ com_android_server_led_LedService.cpp
│ 加载 HAL 模块 │
├──────────────────────────────────────┤
│ HAL (C/C++) │ led.default.so
│ AIDL / HIDL 接口实现 │ ILed::setState()
├──────────────────────────────────────┤
│ Kernel Driver (C) │ /dev/led0
│ 字符设备 / sysfs / 设备树 │ led_write() / led_read()
├──────────────────────────────────────┤
│ Hardware │ GPIO → LED
└──────────────────────────────────────┘
第一层:Linux 内核驱动
1.1 字符设备驱动
c
// drivers/char/led_driver.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/uaccess.h>
#define LED_GPIO 123 // GPIO 编号
static dev_t led_dev;
static struct cdev led_cdev;
static struct class *led_class;
static int led_open(struct inode *inode, struct file *file) {
gpio_direction_output(LED_GPIO, 0);
return 0;
}
static ssize_t led_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) {
char val;
if (copy_from_user(&val, buf, 1)) return -EFAULT;
if (val == '1') {
gpio_set_value(LED_GPIO, 1); // 开灯
} else {
gpio_set_value(LED_GPIO, 0); // 关灯
}
return count;
}
static ssize_t led_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) {
char val = gpio_get_value(LED_GPIO) ? '1' : '0';
if (copy_to_user(buf, &val, 1)) return -EFAULT;
return 1;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
};
static int __init led_init(void) {
// 1. 分配设备号
alloc_chrdev_region(&led_dev, 0, 1, "led");
// 2. 初始化并注册字符设备
cdev_init(&led_cdev, &led_fops);
cdev_add(&led_cdev, led_dev, 1);
// 3. 创建设备节点 /dev/led0
led_class = class_create("led");
device_create(led_class, NULL, led_dev, NULL, "led0");
// 4. 申请 GPIO
gpio_request(LED_GPIO, "led");
return 0;
}
static void __exit led_exit(void) {
gpio_free(LED_GPIO);
device_destroy(led_class, led_dev);
class_destroy(led_class);
cdev_del(&led_cdev);
unregister_chrdev_region(led_dev, 1);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
1.2 设备树配置
dts
// arch/arm64/boot/dts/vendor/board.dts
&i2c0 {
led_controller: led@27 {
compatible = "vendor,led-driver";
gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
label = "status_led";
};
};
1.3 编译进内核
makefile
# drivers/char/Kconfig
config LED_CUSTOM
tristate "Custom LED Device Driver"
depends on GPIOLIB
help
Custom LED driver for Android HAL demo.
# drivers/char/Makefile
obj-$(CONFIG_LED_CUSTOM) += led_driver.o
bash
# defconfig 中启用
CONFIG_LED_CUSTOM=y
第二层:HAL(硬件抽象层)
Android 13+ 推荐使用 AIDL HAL(替代旧版 HIDL)。
2.1 定义 AIDL 接口
aidl
// hardware/interfaces/led/aidl/ILed.aidl
package vendor.myhardware.led;
interface ILed {
void setState(boolean on);
boolean getState();
}
2.2 实现 HAL 模块
cpp
// hardware/interfaces/led/impl/LedImpl.cpp
#include <android/binder_manager.h>
#include <aidl/vendor/myhardware/led/BnLed.h>
using aidl::vendor::myhardware::led::ILed;
using aidl::vendor::myhardware::led::BnLed;
class LedImpl : public BnLed {
public:
LedImpl() {
// 打开字符设备
mFd = open("/dev/led0", O_RDWR);
}
~LedImpl() { if (mFd >= 0) close(mFd); }
ndk::ScopedAStatus setState(bool on) override {
char val = on ? '1' : '0';
write(mFd, &val, 1);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus getState(bool* _aidl_return) override {
char val;
read(mFd, &val, 1);
*_aidl_return = (val == '1');
return ndk::ScopedAStatus::ok();
}
private:
int mFd;
};
int main() {
// 注册 HAL 服务
std::shared_ptr<LedImpl> led = ndk::SharedRefBase::make<LedImpl>();
binder_status_t status = AServiceManager_addService(
led->asBinder().get(), "vendor.myhardware.led.ILed/default"
);
// 加入 binder 线程池
ABinderProcess_setThreadPoolMaxThreadCount(4);
ABinderProcess_startThreadPool();
ABinderProcess_joinThreadPool(); // 阻塞等待调用
return 0;
}
2.3 HAL 编译配置
makefile
# hardware/interfaces/led/aidl/Android.bp
aidl_interface {
name: "vendor.myhardware.led",
vendor: true,
srcs: ["*.aidl"],
backend: {
cpp: { enabled: true },
java: { enabled: true },
ndk: { enabled: true },
},
}
makefile
# hardware/interfaces/led/impl/Android.bp
cc_binary {
name: "vendor.myhardware.led-service",
vendor: true,
init_rc: ["led-service.rc"],
srcs: ["LedImpl.cpp"],
shared_libs: [
"libbinder_ndk",
"libbase",
],
vintf_fragments: ["vendor.myhardware.led.xml"],
}
2.4 服务启动配置
rc
# hardware/interfaces/led/impl/led-service.rc
service vendor.led-service /vendor/bin/hw/vendor.myhardware.led-service
class hal
user system
group system
seclabel u:r:hal_led_default:s0
xml
<!-- hardware/interfaces/led/impl/vendor.myhardware.led.xml -->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>vendor.myhardware.led</name>
<version>1</version>
<interface>
<name>ILed</name>
<instance>default</instance>
</interface>
</hal>
</manifest>
第三层:SELinux 权限
驱动要能正常工作,必须添加 SELinux 策略。
te
# device/vendor/sepolicy/hal_led.te
type hal_led_default, domain;
hal_server_domain(hal_led_default, hal_led)
type hal_led_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_led_default)
# 允许 HAL 访问 /dev/led0
allow hal_led_default led_device:chr_file { read write open ioctl };
# device/vendor/sepolicy/device.te
type led_device, dev_type;
te
# device/vendor/sepolicy/file_contexts
/dev/led0 u:object_r:led_device:s0
/vendor/bin/hw/vendor\.myhardware\.led-service u:object_r:hal_led_default_exec:s0
第四层:JNI(Java Native Interface)
cpp
// frameworks/base/services/core/jni/com_android_server_led_LedService.cpp
#include <jni.h>
#include <android/binder_manager.h>
#include <aidl/vendor/myhardware/led/ILed.h>
using aidl::vendor::myhardware::led::ILed;
static std::shared_ptr<ILed> gLedService;
static void led_init(JNIEnv* env, jobject /* clazz */) {
ndk::SpAIBinder binder = AServiceManager_getService(
"vendor.myhardware.led.ILed/default"
);
gLedService = ILed::fromBinder(binder);
}
static jboolean led_setState(JNIEnv* env, jobject /* clazz */, jboolean on) {
auto status = gLedService->setState(on);
return status.isOk();
}
static jboolean led_getState(JNIEnv* env, jobject /* clazz */) {
bool state = false;
gLedService->getState(&state);
return state ? JNI_TRUE : JNI_FALSE;
}
static JNINativeMethod gMethods[] = {
{"nativeInit", "()V", (void*)led_init},
{"nativeSetState", "(Z)Z", (void*)led_setState},
{"nativeGetState", "()Z", (void*)led_getState},
};
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
vm->GetEnv((void**)&env, JNI_VERSION_1_6);
jclass clazz = env->FindClass("com/android/server/led/LedService");
env->RegisterNatives(clazz, gMethods,
sizeof(gMethods) / sizeof(gMethods[0]));
return JNI_VERSION_1_6;
}
第五层:Framework Service(Java)
java
// frameworks/base/services/core/java/com/android/server/led/LedService.java
package com.android.server.led;
import android.content.Context;
import com.android.server.SystemService;
public class LedService extends SystemService {
// 加载 JNI 库
static {
System.loadLibrary("service-led");
}
private static native void nativeInit();
private static native boolean nativeSetState(boolean on);
private static native boolean nativeGetState();
private final IBinder mBinder = new ILedService.Stub() {
@Override
public void setState(boolean on) {
enforcePermission();
nativeSetState(on);
}
@Override
public boolean getState() {
enforcePermission();
return nativeGetState();
}
};
@Override
public void onStart() {
nativeInit();
publishBinderService(Context.LED_SERVICE, mBinder);
}
}
定义 AIDL(Framework 到 App 的接口)
aidl
// frameworks/base/core/java/android/hardware/led/ILedService.aidl
package android.hardware.led;
interface ILedService {
void setState(boolean on);
boolean getState();
}
第六层:App 调用
kotlin
// app/LedActivity.kt
import android.hardware.led.ILedService
import android.os.ServiceManager
class LedActivity : ComponentActivity() {
private val ledService: ILedService by lazy {
val binder = ServiceManager.getService("led")
ILedService.Stub.asInterface(binder)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.btnOn.setOnClickListener {
ledService.setState(true) // 开灯
}
binding.btnOff.setOnClickListener {
ledService.setState(false) // 关灯
}
}
}
完整调用链
code
App: ledService.setState(true)
│
├─ Binder IPC 跨进程调用
│
▼
Framework: LedService.nativeSetState(true)
│
├─ JNI 调用 C++ 函数
│
▼
JNI: led_setState(true) → gLedService->setState(true)
│
├─ AIDL Binder IPC → HAL Service
│
▼
HAL: LedImpl::setState(true) → write(mFd, "1", 1)
│
├─ syscall write() → 进入内核态
│
▼
Kernel: led_write() → gpio_set_value(LED_GPIO, 1)
│
├─ 写 GPIO 寄存器
│
▼
Hardware: LED 亮起
开发流程总结
| 步骤 | 层 | 产出 | 编译 |
|---|---|---|---|
| 1 | Kernel | led_driver.c + DTS | 内核镜像 |
| 2 | HAL | AIDL + LedImpl.cpp | led-service + .so |
| 3 | SELinux | .te 文件 | sepolicy |
| 4 | JNI | native 注册 | libservice-led.so |
| 5 | Framework | SystemService + AIDL | services.jar |
| 6 | App | Kotlin/Java | APK |
调试命令
bash
# 查看 HAL 服务是否注册
adb shell dumpsys | grep led
# 查看内核日志
adb shell dmesg | grep led
# 手动测试设备节点
adb shell echo 1 > /dev/led0
# 查看 SELinux 拒绝日志
adb shell dmesg | grep avc
# 查看 HAL 服务列表
adb shell service list | grep led
关键配置文件清单
code
project/
├── kernel/
│ └── drivers/char/led_driver.c # 内核驱动
├── hardware/interfaces/led/
│ ├── aidl/
│ │ └── android/hardware/led/ILed.aidl # HAL 接口定义
│ └── impl/
│ ├── LedImpl.cpp # HAL 实现
│ ├── Android.bp # 编译配置
│ ├── led-service.rc # 启动脚本
│ └── vendor.myhardware.led.xml # VINTF 声明
├── device/vendor/sepolicy/
│ ├── hal_led.te # HAL SELinux 策略
│ ├── device.te # 设备类型定义
│ └── file_contexts # 文件上下文
├── frameworks/base/
│ ├── services/core/jni/
│ │ └── com_android_server_led_LedService.cpp # JNI
│ └── core/java/android/hardware/led/
│ └── ILedService.aidl # Framework AIDL
└── app/src/
└── LedActivity.kt # App 调用示例
总结
Android 驱动开发核心原则:
- 分而治之:每层只管自己的事情,通过稳定接口通信
- Kernel 做最小的事:读写寄存器,不处理业务逻辑
- HAL 封装硬件差异:不同硬件换 HAL 实现,上层代码不变
- SELinux 不能忘:缺策略是 Android 驱动开发最常见的坑
- Binder 走天下:HAL → Framework → App 全走 Binder IPC
评论 (0)