Schnelle Nachrichtenwarteschlange mit AIDL

Ab Android 12 kann Fast Message Queue mit AIDL-Schnittstellen über das NDK-Backend verwendet werden. Dadurch können Prozesse nach einer kurzen Einrichtung ohne den Overhead und die Einschränkungen von Binder-Transaktionen kommunizieren. Die Verwendung von Stable AIDL ermöglicht die Kommunikation zwischen System- und Anbieterprozessen.

Unterstützte Nutzlasttypen

Die zwischen Prozessen in der Nachrichtenwarteschlange des gemeinsamen Speichers gesendeten Nachrichten müssen über Prozessgrenzen hinweg das gleiche Speicherlayout haben und dürfen keine Zeiger enthalten. Der Versuch, eine AidlMessageQueue mit einem Typ zu erstellen, der nicht unterstützt wird, führt zu einem Kompilierungsfehler.

Unterstützte Warteschlangentypen

Die gleichen Warteschlangentypen von HIDL, oft auch Flavors genannt, werden von AIDL unterstützt. Diese werden als Vorlagenargumente für die Warteschlangen und Deskriptoren verwendet.

HIDL-Typen AIDL-Typen
android::hardware::kSynchronizedReadWrite android.hardware.common.fmq.SynchronizedReadWrite
android::hardware::kUnsynchronizedWrite android.hardware.common.fmq.UnsynchronizedWrite

Wie benutzt man

Definieren Sie die AIDL-Schnittstelle, die den MQDescriptor an den anderen Prozess übergibt. MQDescriptor kann überall dort verwendet werden, wo sich ein Parcelable befinden kann.

Die erforderlichen Vorlagenargumente für MQDescriptor sind der Nutzlasttyp und die Warteschlangenart.

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

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

Der Prozess zum Einrichten jeder Seite der Nachrichtenwarteschlange ist nahezu identisch mit dem Prozess bei Verwendung von HIDL , es werden lediglich die AIDL-Typen verwendet.

#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);

Der Empfangsprozess erstellt die andere Seite der Warteschlange mit dem von der AIDL-Schnittstelle empfangenen Deskriptor.

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()) {
   ...
}

Die Verwendung der AidlMessageQueue nach dem Setup ist dieselbe wie die der HIDL MessageQueue . Alle unter Verwenden der MessageQueue beschriebenen APIs werden von AidlMessageQueue vollständig unterstützt, mit einer Ausnahme:

const MQDescriptor<T, flavor>* getDesc() wird durch MQDescriptor<T, U> dupeDesc() ersetzt, das den AIDL MQDescriptor zurückgibt.