3. AIDL基础回顾:AIDL接口定义语言语法、服务注册与发现机制(Android 11+)

在深入AIDL化Camera HAL架构之前,必须牢固掌握AIDL(Android Interface Definition Language)的核心基础。本章聚焦于AIDL的接口定义语法、数据类型映射以及Android 11+引入的服务注册与发现机制,为后续理解Camera HAL从HIDL到AIDL的迁移奠定语法与架构基础。

3.1 AIDL接口定义语言语法

AIDL是一种轻量级的接口定义语言,用于定义客户端与服务端之间的进程间通信(IPC)契约。其语法与Java接口高度相似,但仅支持方法声明、参数和返回值类型,不支持访问修饰符、静态成员或内部类。

3.1.1 基本语法结构

一个标准的AIDL文件以包声明开头,随后导入依赖类型,最后定义接口。接口中的方法支持in、out、inout方向标记,用于指示参数的数据流向。

// ICameraDevice.aidl
package android.hardware.camera;

import android.hardware.camera.CameraMetadata;

interface ICameraDevice {
    int open(String cameraId);
    void close();
    CameraMetadata getCharacteristics(in String cameraId);
    int setCallback(in ICameraDeviceCallback callback);
    CaptureResult capture(in CaptureRequest request, out ParcelFileDescriptor fd);
}

3.1.2 数据类型映射规则

AIDL支持的数据类型分为三类:基本类型、Parcelable类型和AIDL接口类型。下表列出了常用类型及其映射关系:

AIDL类型 Java类型 C++类型 方向支持
boolean boolean bool in
int int int32_t in
long long int64_t in
float float float in
double double double in
String String std::string in
List<T> List<T> std::vector<T> in/out
Map<K,V> Map<K,V> std::map<K,V> in/out
IBinder IBinder android::IBinder in
ParcelFileDescriptor ParcelFileDescriptor android::os::ParcelFileDescriptor in/out
关键提示:在Camera HAL的AIDL化过程中,ParcelFileDescriptor用于传递Camera buffer的共享内存fd,IBinder用于传递回调接口。方向标记in表示数据从客户端流向服务端,out表示从服务端流向客户端,inout表示双向流动。错误使用方向标记会导致序列化异常。

3.1.3 自定义Parcelable类型

对于复杂数据结构,需要定义Parcelable类型。在AIDL中,Parcelable类型必须显式声明,并实现Parcelable接口。

// CameraMetadata.aidl
package android.hardware.camera;

parcelable CameraMetadata {
    String cameraId;
    int sensorOrientation;
    long exposureTime;
    float aperture;
    List<int> availableFpsRanges;
}

对应的Java实现类必须包含writeToParcel()和CREATOR字段:

public class CameraMetadata implements Parcelable {
    public String cameraId;
    public int sensorOrientation;
    public long exposureTime;
    public float aperture;
    public List<Integer> availableFpsRanges;

    protected CameraMetadata(Parcel in) {
        cameraId = in.readString();
        sensorOrientation = in.readInt();
        exposureTime = in.readLong();
        aperture = in.readFloat();
        availableFpsRanges = in.createIntArrayList();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(cameraId);
        dest.writeInt(sensorOrientation);
        dest.writeLong(exposureTime);
        dest.writeFloat(aperture);
        dest.writeIntList(availableFpsRanges);
    }

    public static final Creator<CameraMetadata> CREATOR =
            new Creator<CameraMetadata>() {
                @Override
                public CameraMetadata createFromParcel(Parcel in) {
                    return new CameraMetadata(in);
                }
                @Override
                public CameraMetadata[] newArray(int size) {
                    return new CameraMetadata[size];
                }
            };
}

3.2 AIDL服务注册与发现机制(Android 11+)

Android 11(API 30)对AIDL服务注册与发现机制进行了重大重构,引入了稳定的AIDL(Stable AIDL)概念,使得AIDL接口可以像HIDL一样作为系统API稳定发布。这一变化是Camera HAL从HIDL迁移到AIDL的核心驱动力。

3.2.1 服务注册流程

在Android 11+中,AIDL服务通过ServiceManager进行注册,但注册方式与早期版本有显著区别:

  1. 定义稳定AIDL接口:接口文件必须位于hardware/interfaces/或frameworks/hardware/interfaces/目录下,并遵循版本化命名规范。
  2. 实现服务端:继承生成的Stub类,实现接口方法。
  3. 注册服务:使用ServiceManager.addService()将Binder对象注册到全局服务管理器。
  4. 声明服务:在manifest.xml中声明服务进程和接口版本。
// 服务端注册示例(C++)
#include <android/binder_manager.h>
#include <android/binder_service.h>

class CameraDeviceService : public ICameraDevice {
    ndk::ScopedAStatus open(const std::string& cameraId, int32_t* _aidl_return) override {
        // 实现逻辑
        *_aidl_return = 0;
        return ndk::ScopedAStatus::ok();
    }
    // 其他方法实现...
};

int main() {
    auto service = ndk::SharedRefBase::make<CameraDeviceService>();
    const std::string instance = std::string() + ICameraDevice::descriptor + "/default";
    binder_status_t status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
    if (status != STATUS_OK) {
        // 错误处理
    }
    // 进入消息循环
    ABinderProcess_joinThreadPool();
    return 0;
}

3.2.2 服务发现机制

客户端通过ServiceManager查询服务实例,获取Binder代理对象。Android 11+推荐使用AServiceManager_getService()或getService()模板函数:

// 客户端发现服务示例(C++)
#include <android/binder_manager.h>

void connectToCameraService() {
    const std::string instance = std::string() + ICameraDevice::descriptor + "/default";
    ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
    if (!binder) {
        // 服务未就绪,重试或报错
        return;
    }
    auto service = ICameraDevice::fromBinder(binder);
    if (!service) {
        // 接口不匹配
        return;
    }
    int32_t result;
    ndk::ScopedAStatus status = service->open("0", &result);
    if (status.isOk()) {
        // 成功调用
    }
}
重要区别:与HIDL使用hwservicemanager不同,AIDL服务统一使用servicemanager(即ServiceManager)。这意味着Camera HAL的AIDL服务与Android系统其他AIDL服务共享同一个命名空间,实例名称必须全局唯一,通常采用接口描述符/实例名的格式。

3.2.3 服务注册与发现架构图

下图展示了Android 11+中AIDL服务的完整注册与发现流程,以及客户端与服务端之间的IPC通信路径:

Android 11+ AIDL服务注册与发现架构 Camera HAL服务进程 实现ICameraDevice接口 addService() ServiceManager 全局服务注册表 Camera客户端进程 CameraService / App getService() 返回Binder代理 Binder驱动 内核IPC通道 说明: 1. 服务端通过AServiceManager_addService()注册到ServiceManager,实例名格式为"接口描述符/实例名"。 2. 客户端通过AServiceManager_getService()查询服务,获取Binder代理后调用接口方法。 3. 实际IPC数据通过Binder驱动在内核空间传递,ServiceManager仅负责服务发现。

3.3 AIDL与HIDL服务注册对比

理解AIDL与HIDL在服务注册与发现机制上的差异,是掌握Camera HAL迁移的关键。下表从多个维度进行对比:

对比维度 AIDL(Android 11+) HIDL
服务管理器 ServiceManager(servicemanager进程) hwservicemanager(独立进程)
接口描述符 android.hardware.camera.ICameraDevice android.hardware.camera@3.4::ICameraDevice
实例名称格式 接口描述符/实例名(如 .../default) 接口描述符/实例名(如 .../default)
注册API AServiceManager_addService() registerAsService()
发现API AServiceManager_getService() getService()
接口稳定性 稳定AIDL(版本化,冻结后不可修改) HIDL(版本化,冻结后不可修改)
传输层 Binder(内核驱动) Binderized HIDL(Binder驱动)或Passthrough(直通模式)
客户端语言 Java / C++ / Rust / NDK Java / C++(主要)
服务端语言 Java / C++ / Rust / NDK Java / C++
架构洞察:AIDL化Camera HAL的核心优势在于统一了服务注册与发现机制。在HIDL时代,Camera HAL需要同时维护hwservicemanager和servicemanager两套服务注册表,增加了系统复杂性和调试难度。迁移到AIDL后,所有系统服务(包括Camera HAL)共享同一个ServiceManager,简化了服务发现流程,降低了跨进程通信的维护成本。

3.4 稳定AIDL接口版本化规则

Android 11+引入的稳定AIDL要求接口必须版本化,且一旦发布冻结,不允许修改已有方法。版本化规则如下:

  • 接口文件命名:ICameraDevice.aidl(无版本号),版本信息通过目录结构体现。
  • 目录结构:hardware/interfaces/camera/aidl/android.hardware.camera/,版本号在current.txt中定义。
  • 版本冻结:每个版本发布后,接口文件被复制到对应版本目录(如aidl/android.hardware.camera-V1/),后续版本只能新增方法,不能修改或删除已有方法。
  • 向后兼容:服务端可以同时实现多个版本接口,客户端通过getInterfaceVersion()查询服务端支持的版本。
// 版本查询示例
ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
auto service = ICameraDevice::fromBinder(binder);
if (service) {
    int32_t version = service->getInterfaceVersion();
    if (version >= 2) {
        // 调用V2新增的方法
    }
}

3.5 本章小结

本章系统回顾了AIDL的核心基础:接口定义语法支持基本类型、Parcelable类型和AIDL接口类型,方向标记in/out/inout控制数据流向;Android 11+的服务注册与发现机制统一使用ServiceManager,通过AServiceManager_addService()和AServiceManager_getService()实现;稳定AIDL的版本化规则确保了接口的长期兼容性。这些基础概念是理解后续Camera HAL AIDL化实践的前提。