Fast Message Queue with AIDL

从 Android 12 开始,快速消息队列可以与使用 NDK 后端的 AIDL 接口结合使用。这样一来,进程便可在进行一些简短设置后进行通信,而不会产生 Binder 事务的开销和限制。Stable AIDL 支持系统进程和供应商进程之间的通信。

支持的载荷类型

在共享内存消息队列中进程之间发送的消息必须在进程边界之间具有相同的内存布局,并且不能包含指针。尝试使用不受支持的类型创建 AidlMessageQueue 会导致编译错误。

支持的队列类型

AIDL 支持与 HIDL 中相同的队列类型(通常称为“变体”)。这些类型用作队列和描述符的模板参数。

HIDL 类型 AIDL 类型
android::hardware::kSynchronizedReadWrite android.hardware.common.fmq.SynchronizedReadWrite
android::hardware::kUnsynchronizedWrite android.hardware.common.fmq.UnsynchronizedWrite

使用方法

定义 AIDL 接口,用于将 MQDescriptor 传递给其他进程。MQDescriptor 可在任何可以使用 parcelable 的地方使用。

MQDescriptor 所需的模板参数是 payload 类型和队列 flavor。

import android.hardware.common.fmq.MQDescriptor
import android.hardware.common.fmq.SynchronizedReadWrite

void getQueue(out MQDescriptor<int, SynchronizedReadWrite> mqDesc);

消息队列每一端的设置过程与使用 HIDL 的过程几乎相同,只是使用了 AIDL 类型。

#include <fmq/AidlMessageQueue.h>
...
using ::android::AidlMessageQueue;
using ::aidl::android::hardware::common::fmq::MQDescriptor;
using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
...
ndk::ScopedAStatus MyInterface::getQueue(MQDescriptor<int32_t, SynchronizedReadWrite>* mqDesc) {
    *mqDesc = mFmqSynchronized->dupeDesc();
    return ndk::ScopedAStatus::ok();
}
...
// Create the first side of the queue before servicing getQueue() in this example
mFmqSynchronized =
  new AidlMessageQueue<int32_t, SynchronizedReadWrite>(kNumElementsInQueue);

接收进程将使用从 AIDL 接口接收的描述符创建队列的另一端。

MQDescriptor<int32_t, SynchronizedReadWrite> desc;
auto ret = service->getQueue(true, &desc);
if (!ret.isOk()) {
   ...
}
// By default the constructor will reset the read and write pointers of the queue.
// Add a second `false` argument to avoid resetting the pointers.
mQueue = new (std::nothrow) AidlMessageQueue<int32_t, SynchronizedReadWrite>(desc);
if (!mQueue->isValid()) {
   ...
}

设置后使用 AidlMessageQueue 与 HIDL MessageQueue 相同。使用 MessageQueue 中描述的所有 API 都完全受 AidlMessageQueue 支持,但有一个例外。

const MQDescriptor<T, flavor>* getDesc()MQDescriptor<T, U> dupeDesc() 取代,后者返回 AIDL MQDescriptor