Journal Article

Android 系统驱动开发流程详解

从Linux内核驱动层到HAL硬件抽象层,再到JNI和Framework Service,完整覆盖Android系统驱动开发全流程。包含字符设备驱动、设备树配置、HIDL/AIDL HAL实现、SELinux策略和App层调用示例。

24 min2 views

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 亮起

开发流程总结

步骤产出编译
1Kernelled_driver.c + DTS内核镜像
2HALAIDL + LedImpl.cppled-service + .so
3SELinux.te 文件sepolicy
4JNInative 注册libservice-led.so
5FrameworkSystemService + AIDLservices.jar
6AppKotlin/JavaAPK

调试命令

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 驱动开发核心原则:

  1. 分而治之:每层只管自己的事情,通过稳定接口通信
  2. Kernel 做最小的事:读写寄存器,不处理业务逻辑
  3. HAL 封装硬件差异:不同硬件换 HAL 实现,上层代码不变
  4. SELinux 不能忘:缺策略是 Android 驱动开发最常见的坑
  5. Binder 走天下:HAL → Framework → App 全走 Binder IPC