Szybka kolejka wiadomości z AIDL

Od Androida 12 można używać szybkiej kolejki wiadomości z interfejsami AIDL korzystającymi z backendu NDK. Umożliwia to procesom komunikowanie się bez obciążenia i ograniczeń transakcji binderowych po krótkiej konfiguracji. Korzystanie ze stabilnego AIDL umożliwia komunikację między procesami systemowymi i procesami dostawcy.

Obsługiwane typy ładunków

  • FixedSize typy AIDL parcelable (niedostępne w backendzie cpp)
  • Typy AIDL union (niedostępne w backendzie cpp)
  • Typy AIDL enum
  • Typy AIDL integral

Wiadomości wysyłane między procesami w kolejce wiadomości w pamięci współdzielonej muszą mieć ten sam układ pamięci w obrębie granic procesu i nie mogą zawierać wskaźników. Próba utworzenia AidlMessageQueue z typem, który nie jest obsługiwany, powoduje błąd kompilacji. Typów AIDL parcelable i union w backendzie cpp nie można używać z szybką kolejką wiadomości, ponieważ dziedziczą one po android::Parcelable, która ma funkcje wirtualne.

Obsługiwane typy kolejek

W AIDL są obsługiw101ane te same typy kolejek co w HIDL, często nazywane wariantami. Są one używane jako argumenty szablonu dla kolejek i deskryptorów.

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

Instrukcje korzystania

Zdefiniuj interfejs AIDL, który przekazuje MQDescriptor do innego procesu. MQDescriptor można używać wszędzie tam, gdzie można używać typu parcelable.

Wymagane argumenty szablonu dla MQDescriptor to typ ładunku i wariant kolejki.

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

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

Proces konfigurowania każdej strony kolejki wiadomości jest prawie identyczny z procesem korzystającym z HIDL, tylko z użyciem typów 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);

Proces odbierający tworzy drugą stronę kolejki za pomocą deskryptora otrzymanego z interfejsu 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()) {
   ...
}

Korzystanie z AidlMessageQueue po konfiguracji jest takie samo jak w przypadku MessageQueue HIDL. Wszystkie interfejsy API opisane w sekcji Korzystanie z MessageQueue są w pełni obsługiwane przez AidlMessageQueue z jednym wyjątkiem:

const MQDescriptor<T, flavor>* getDesc() jest zastępowany przez MQDescriptor<T, U> dupeDesc() który zwraca AIDL MQDescriptor.