使用 AIDL 快速將訊息排入佇列

自 Android 12 起,快速訊息佇列可用於使用 NDK 後端的 AIDL 介面。這樣一來,在經過短暫設定後,程序就能進行通訊,而不會受到繫結器交易的額外負擔和限制。使用 Stable AIDL 可讓系統與供應商程序之間進行通訊。

支援的酬載類型

在共用記憶體訊息佇列中,於程序之間傳送的訊息,必須在各個程序邊界內採用相同的記憶體配置,且不得包含指標。如果嘗試使用不支援的類型建立 AidlMessageQueue,就會導致編譯錯誤。

支援的佇列類型

AIDL 支援 HIDL 中的相同佇列類型,通常稱為變種。這些會用作佇列和描述元的範本引數。

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

使用方法

定義將 MQDescriptor 傳遞至其他程序的 AIDL 介面。 MQDescriptor 可用於任何可使用 parcelable 的地方。

MQDescriptor 的必要範本引數為酬載類型和佇列類型。

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