2. AIDL基础与核心概念:语法、数据类型、定向tag与oneway

在Camera HAL多进程架构中,AIDL(Android Interface Definition Language)是连接Framework与HAL Service的通信契约。本章聚焦AIDL的核心语法、数据类型映射规则、参数定向tag(in/out/inout)以及oneway关键字的底层行为,为后续调试AIDL服务提供理论基石。

2.1 AIDL语法结构

AIDL文件定义了一个跨进程接口,其语法与Java接口高度相似,但仅支持方法声明,不支持静态常量、内部类或方法体。一个标准的AIDL接口包含包声明、导入语句、接口定义与方法签名。

核心语法规则:
  • 文件扩展名必须为 .aidl,且文件名与接口名一致。
  • 包名必须与文件所在目录结构匹配。
  • 非默认类型的参数(如自定义Parcelable)必须显式import。
  • 所有非void方法必须指定返回值类型。
  • 参数前必须标注定向tag:in、out或inout。
// ICameraService.aidl
package android.hardware.camera;

import android.hardware.camera.CameraMetadata;  // 自定义Parcelable

interface ICameraService {
    int openCamera(in String cameraId, in ICameraClient client);
    CameraMetadata getCameraCharacteristics(in String cameraId);
    void setTorchMode(in String cameraId, boolean enabled);
    void notifyCameraState(in String cameraId, int newState);
}
工程提示:在Camera HAL中,ICameraClient通常是一个oneway回调接口,用于从服务端向客户端异步推送帧数据或事件,避免阻塞服务端线程。

2.2 数据类型映射

AIDL支持的数据类型分为三类:基本类型、Parcelable类型与AIDL接口类型。下表列出了Camera HAL开发中最常用的映射关系:

AIDL类型 Java类型 C++类型(NDK后端) Camera HAL典型用途
int int int32_t 错误码、状态枚举、帧编号
long long int64_t 时间戳、帧序号
boolean boolean bool 开关状态、功能支持标志
String String std::string CameraId、配置参数键值
List<T> ArrayList<T> std::vector<T> 支持的预览尺寸列表、人脸数组
Map<K,V> HashMap<K,V> std::unordered_map<K,V> 元数据键值对、扩展配置
Parcelable 实现Parcelable的类 实现Parcelable的结构体 CameraMetadata、CaptureRequest
IBinder IBinder sp<IBinder> 回调接口传递、服务引用
避坑指南:在Camera HAL的AIDL接口中,List<Integer>或List<Long>等包装类型会触发自动装箱/拆箱,在频繁调用的热点路径(如每帧元数据回调)中会产生大量临时对象,建议使用int[]或long[]原始数组替代。

2.3 定向tag:in / out / inout

定向tag定义了参数在跨进程传输时的数据流向,直接影响Binder驱动的序列化与反序列化行为。理解tag的语义是避免数据丢失或性能浪费的关键。

定向tag数据流向示意图 客户端进程 服务端进程 Binder驱动 序列化 / 反序列化 / 缓存 in out inout(双向传输) 定向tag行为说明: • in:客户端→服务端。服务端修改参数不影响客户端。默认tag,性能最优。 • out:服务端→客户端。客户端传入的值被忽略,服务端写入后返回。 • inout:双向传输。客户端传入,服务端可修改,修改结果返回客户端。开销最大。
Camera HAL中的tag选择策略:
  • in:用于配置参数(如CameraId、预览尺寸)、控制命令(如startPreview)。服务端无需回传修改值。
  • out:用于获取状态(如getCameraCharacteristics),客户端传入空对象,服务端填充数据后返回。
  • inout:极少使用。仅在需要服务端修改并返回复杂对象(如自定义配置结构体)时使用,会触发两次序列化/反序列化,增加Binder负载。

2.4 oneway关键字

oneway关键字修饰AIDL方法,表示该方法为异步调用。调用方在发送请求后立即返回,不等待服务端处理完成。在Camera HAL中,oneway常用于回调接口和事件通知,以避免服务端阻塞客户端。

// 回调接口示例:ICameraCallback.aidl
package android.hardware.camera;

oneway interface ICameraCallback {
    void onFrameAvailable(in long timestamp);
    void onError(in int errorCode, in String errorMsg);
    void onCameraDisconnected();
}
特性 同步调用(默认) oneway异步调用
调用方阻塞 是,等待服务端返回 否,立即返回
返回值 支持(void或非void) 仅支持void
out/inout参数 支持 不支持(无返回通道)
Binder线程池占用 占用一个服务端线程直到返回 服务端线程池可立即处理下一个请求
异常传播 RemoteException可捕获 RemoteException在调用方不可见(异步)
Camera HAL典型场景 openCamera、setParameters 帧回调、错误通知、状态变化
性能陷阱:在Camera HAL中,如果错误地将高频回调(如每帧30fps的onFrameAvailable)声明为同步调用,会导致服务端Binder线程池迅速耗尽,引发ANR或帧丢失。务必使用oneway修饰所有回调接口。

2.5 综合示例:Camera HAL AIDL接口定义

以下是一个简化的Camera HAL AIDL接口,综合运用了上述所有核心概念:

// ICameraHalService.aidl
package android.hardware.camera.hal;

import android.hardware.camera.hal.CameraConfig;
import android.hardware.camera.hal.ICameraHalCallback;

interface ICameraHalService {
    // 同步:打开相机,返回会话句柄
    int openCamera(in String cameraId, out CameraConfig config);

    // 同步:配置预览参数
    boolean configureStreams(in int streamType, in int width, in int height);

    // 同步:获取元数据(out参数)
    void getCameraMetadata(in String cameraId, out byte[] metadata);

    // 异步:注册回调接口(oneway)
    oneway void setCallback(in ICameraHalCallback callback);

    // 异步:触发捕获(oneway,无返回值)
    oneway void triggerCapture(in int captureId);
}

// ICameraHalCallback.aidl
package android.hardware.camera.hal;

oneway interface ICameraHalCallback {
    void onCaptureCompleted(in int captureId, in long timestamp);
    void onError(in int errorCode);
}
Camera HAL AIDL接口调用流程 Camera App HAL Service openCamera (同步, in/out) 返回句柄 + config setCallback (oneway, 异步) onCaptureCompleted (oneway回调) 关键设计点: • 同步调用(openCamera)使用in/out tag传递参数和返回值,保证原子性。 • 回调接口(ICameraHalCallback)声明为oneway,避免服务端线程阻塞客户端帧接收线程。
调试要点:在调试AIDL多进程通信时,可通过adb shell dumpsys binder查看Binder线程池使用情况。如果发现服务端线程池耗尽,优先检查是否将高频回调错误地声明为同步调用,或out/inout参数导致不必要的序列化开销。