Szybka kolejka wiadomości z AIDL

Od Androida 12 szybka kolejka wiadomości może być używana z interfejsami AIDL korzystającymi z backendu NDK. Umożliwia to procesom komunikowanie się bez obciążenia i ograniczeń transakcji Binder po krótkiej konfiguracji. Korzystanie ze stabilnego AIDL umożliwia komunikację między procesami systemowymi a 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 całkowite AIDL

Wiadomości wysyłane między procesami w kolejce komunikatów pamięci współdzielonej muszą mieć ten sam układ pamięci w różnych procesach i nie mogą zawierać wskaźników. Próba utworzenia AidlMessageQueue z użyciem typu, który nie jest obsługiwany, powoduje błąd kompilacji. Typów AIDL parcelableunioncpp backendzie nie można używać z szybką kolejką komunikatów, ponieważ dziedziczą one z android::Parcelable, która ma funkcje wirtualne.

Obsługiwane typy kolejek

W AIDL obsługiwane są te same typy kolejek z 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ć obiektu Parcelable.

Wymagane argumenty szablonu dla funkcji MQDescriptor to typ ładunku i rodzaj 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 komunikatów jest niemal identyczny z procesem z użyciem 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 odbierania tworzy drugą stronę kolejki z deskryptorem otrzymanym 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 HIDL MessageQueue. Wszystkie interfejsy API opisane w artykule Korzystanie z kolejki komunikatów są w pełni obsługiwane w przypadku AidlMessageQueue z jednym wyjątkiem:

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