1. 创建第一个HAL模块

任务目标

在AOSP源码树中创建一个最小HAL模块hello,包含公共头文件、模块源文件和Android.bp构建脚本,编译生成共享库libhello,并通过临时测试程序验证模块接口可被正确调用。

环境与前置条件

  • AOSP源码树已初始化,环境已加载(source build/envsetup.sh,lunch已选择目标)。
  • 以下路径为示例,实际操作时替换为你的源码根目录。

目录结构与文件

在AOSP源码树中创建以下文件:

hardware/sample/hello/
├── include/hello.h
├── hello.c
└── Android.bp

include/hello.h

#ifndef HELLO_HAL_H
#define HELLO_HAL_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#define HELLO_MODULE_ID "hello"

typedef struct hello_device {
    int (*get_version)(struct hello_device* dev, uint32_t* version);
} hello_device_t;

int hello_open(const char* id, hello_device_t** device);
void hello_close(hello_device_t* device);

#ifdef __cplusplus
}
#endif

#endif

hello.c

#include <string.h>
#include <stdlib.h>
#include <log/log.h>
#include "hello.h"

#define HELLO_VERSION 0x0100

static int hello_get_version(struct hello_device* dev, uint32_t* version) {
    if (!version) return -EINVAL;
    *version = HELLO_VERSION;
    return 0;
}

int hello_open(const char* id, hello_device_t** device) {
    if (!id || !device || strcmp(id, HELLO_MODULE_ID) != 0)
        return -EINVAL;

    hello_device_t* dev = calloc(1, sizeof(hello_device_t));
    if (!dev) return -ENOMEM;

    dev->get_version = hello_get_version;
    *device = dev;
    return 0;
}

void hello_close(hello_device_t* device) {
    free(device);
}

Android.bp

cc_library_shared {
    name: "libhello",
    vendor_available: true,
    srcs: ["hello.c"],
    export_include_dirs: ["include"],
    shared_libs: ["liblog"],
}

编译

cd <AOSP根目录>
mmm hardware/sample/hello

编译产物:out/target/product/<target>/system/lib64/libhello.so(64位)或.../system/lib/libhello.so(32位)。

验证方法

在hardware/sample/hello/下创建临时测试文件test_hello.c:

#include <stdio.h>
#include "hello.h"

int main() {
    hello_device_t* dev = NULL;
    uint32_t ver = 0;
    if (hello_open(HELLO_MODULE_ID, &dev) != 0) return 1;
    if (dev->get_version(dev, &ver) != 0) return 2;
    printf("version=0x%04x\n", ver);
    hello_close(dev);
    return 0;
}

编译并运行:

# 在AOSP环境内
clang test_hello.c -I include -L $OUT/system/lib64 -lhello -o test_hello
# 将 libhello.so 与 test_hello 推送到设备或模拟器同一目录
adb push $OUT/system/lib64/libhello.so /data/local/tmp/
adb push test_hello /data/local/tmp/
adb shell "cd /data/local/tmp && LD_LIBRARY_PATH=. ./test_hello"

通过条件:程序输出version=0x0100且退出码为0。该输出由hello_get_version中HELLO_VERSION宏直接决定,与代码逻辑严格一致。

常见问题

  • 头文件找不到:确认export_include_dirs路径正确,且编译时-I指向include目录。
  • 链接错误:检查shared_libs是否包含liblog;测试程序链接时需用-L指定库路径。
  • 设备端无法加载:确认libhello.so已推送到设备且权限为可读(chmod 644),使用LD_LIBRARY_PATH指向库所在目录。
hardware/sample/hello/ include/hello.h - hello_device_t 结构 - hello_open/close 声明 - HELLO_MODULE_ID 宏 hello.c - hello_get_version() - hello_open() 分配内存 - hello_close() 释放 - 版本号 0x0100 Android.bp - cc_library_shared - name: "libhello" - export_include_dirs mmm 编译 Android.bp → ninja libhello.so system/lib64/libhello.so test_hello.c 编译链接 clang -I include -L $OUT/system/lib64 -lhello adb push & 运行 LD_LIBRARY_PATH=. ./test_hello 预期输出: version=0x0100