Android 接口和架构

Android 可让您自由实现您自己的设备规格和驱动程序。硬件抽象层 (HAL) 提供了一种用于在 Android 平台堆叠和硬件之间创建软件钩的标准方法。Android 操作系统也是开放源代码系统,因此您可以贡献您自己的接口和增强功能。

为确保设备能够保持较高的质量水平并提供一致的用户体验,每部设备都必须通过兼容性测试套件 (CTS) 中的测试。CTS 可验证设备是否符合一定的质量标准,此类标准可确保应用稳定运行并提供良好的用户体验。若想详细了解 CTS,请参阅兼容性

在将 Android 移植到您的硬件之前,请花点时间从更高层面上了解 Android 系统架构。由于您的驱动程序和 HAL 会与 Android 进行交互,因此了解 Android 的工作原理可帮助您浏览 Android 开放源代码项目 (AOSP) 源代码树中的多个代码层。

图 1. Android 系统架构

应用框架

应用框架最常被应用开发者使用。作为硬件开发者,您应该非常了解开发者 API,因为很多此类 API 都可直接映射到底层 HAL 接口,并可提供与实现驱动程序相关的实用信息。

Binder IPC

Binder 进程间通信 (IPC) 机制允许应用框架跨越进程边界并调用 Android 系统服务代码,从而使得高级框架 API 能与 Android 系统服务进行交互。在应用框架级别,开发者无法看到此类通信的过程,但一切似乎都在“按部就班地运行”。

系统服务

应用框架 API 所提供的功能可与系统服务通信,以访问底层硬件。服务是集中的模块化组件,例如窗口管理器、搜索服务或通知管理器。Android 包含两组服务:“系统”(诸如窗口管理器和通知管理器之类的服务)和“媒体”(与播放和录制媒体相关的服务)。

硬件抽象层 (HAL)

硬件抽象层 (HAL) 会定义一个标准接口以供硬件供应商实现,并允许 Android 忽略较低级别的驱动程序实现。借助 HAL,您可以顺利实现相关功能,而不会影响或无需更改更高级别的系统。HAL 实现会被封装成模块 (.so) 文件,并会由 Android 系统适时地加载。

图 2. 硬件抽象层 (HAL) 组件

您必须为您的产品所提供的特定硬件实现相应的 HAL(和驱动程序)。HAL 实现通常会内置在共享库模块(.so 文件)中。Android 并不要求您的 HAL 实现与设备驱动程序之间进行标准交互,因此您可以自由地根据您的具体情况执行适当的操作。不过,要使 Android 系统能够与您的硬件正确互动,您必须遵守各个针对特定硬件的 HAL 接口中定义的合同。

标准 HAL 结构

每个针对特定硬件的 HAL 接口均具有 hardware/libhardware/include/hardware/hardware.h 中定义的属性,这些属性可保证 HAL 具有可预测的结构。此类接口允许 Android 系统以一致的方式加载 HAL 模块的正确版本。HAL 接口包含两个通用组件:一个模块和一个设备。

模块表示被封装且存储为共享库 (.so file) 的 HAL 实现。它会包含模块的版本、名称和作者等元数据,这些元数据有助于 Android 找到并正确加载该模块。hardware/libhardware/include/hardware/hardware.h 标头文件会定义一个表示模块的结构体 (hw_module_t),其中会包含模块的版本、作者和名称等信息。

另外,hw_module_t 结构体还会包含一个指向另一结构体 hw_module_methods_t 的指针,后面这个结构体则会包含一个指向相应模块的“open”函数的指针。该“open”函数用于与相关硬件(此 HAL 是其抽象形式)建立通信。每个针对特定硬件的 HAL 通常都会使用附加信息为该特定硬件扩展通用的 hw_module_t 结构体。例如,在相机 HAL 中,camera_module_t 结构体会包含一个 hw_module_t 结构体以及其他针对相机的函数指针:

typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
} camera_module_t;

当您实现 HAL 并创建模块结构体时,必须将其命名为 HAL_MODULE_INFO_SYM。例如,以下是 Nexus 9 音频 HAL 的示例:

struct audio_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = AUDIO_HARDWARE_MODULE_ID,
        .name = "NVIDIA Tegra Audio HAL",
        .author = "The Android Open Source Project",
        .methods = &hal_module_methods,
    },
};

设备会提取产品的实际硬件。例如,音频模块可能会包含主音频设备、USB 音频设备或蓝牙 A2DP 音频设备。设备由 hw_device_t 结构体表示。与模块类似,每类设备都会为通用的 hw_device_t 定义一个更详细的版本,其中会包含指向硬件特定功能的函数指针。例如,audio_hw_device_t 结构体类型会包含指向音频设备操作的函数指针:

struct audio_hw_device {
    struct hw_device_t common;

    /**
     * used by audio flinger to enumerate what devices are supported by
     * each audio_hw_device implementation.
     *
     * Return value is a bitmask of 1 or more values of audio_devices_t
     */
    uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);
  ...
};
typedef struct audio_hw_device audio_hw_device_t;

除了这些标准属性之外,每个针对特定硬件的 HAL 接口都可以定义更多的自有特性和要求。若想详细了解如何实现某个特定接口,请参阅 HAL 参考文档以及各 HAL 的单独说明。

HAL 模块

HAL 实现会内置在模块 (.so) 文件中,并会由 Android 适时地动态关联。您可通过为每个 HAL 实现创建 Android.mk 文件并指向源文件来构建模块。一般来说,您的共享库必须以某种格式命名,以便被找到并正确加载。各模块的命名方案略有不同,但它们都遵循以下通用模式:<module_type>.<device_name>

若想详细了解如何为每个 HAL 设置模块构建,请参阅各 HAL 对应的文档。

Linux 内核

开发设备驱动程序与开发典型的 Linux 设备驱动程序类似。Android 使用的 Linux 内核版本包含一些特殊的补充功能,例如:唤醒锁(这是一种内存管理系统,可更主动地保护内存)、Binder IPC 驱动程序以及对移动嵌入式平台非常重要的其他功能。这些补充功能主要用于增强系统功能,不会影响驱动程序开发。

您可以使用任一版本的内核,只要它支持所需功能(如 Binder 驱动程序)。不过,我们建议您使用 Android 内核的最新版本。若想详细了解 Android 内核的最新版本,请参阅构建内核