Cola de mensajes rápidos con AIDL

A partir de Android 12, se puede usar la cola de mensajes rápidos con interfaces AIDL mediante el backend de NDK. Esto permite que los procesos se comuniquen sin la sobrecarga ni las restricciones de las transacciones de binder después de una configuración breve. El uso de AIDL estable permite la comunicación entre los procesos del sistema y del proveedor.

Tipos de cargas útiles admitidos

  • FixedSize tipos parcelable AIDL (no disponibles en el backend de cpp)
  • Tipos union de AIDL (no disponibles en el backend de cpp)
  • Tipos enum de AIDL
  • Tipos integrales de AIDL

Los mensajes que se envían entre procesos en la cola de mensajes de memoria compartida deben tener el mismo diseño de memoria en los límites del proceso y no pueden contener punteros. Si intentas crear una AidlMessageQueue con un tipo no compatible, se producirá un error de compilación. Los tipos parcelable y union de AIDL en el backend de cpp no se pueden usar con la cola de mensajes rápidos porque heredan de android::Parcelable, que tiene funciones virtuales.

Tipos de colas admitidos

Los mismos tipos de colas de HIDL, que a menudo se denominan variantes, son compatibles con AIDL. Estos se usan como argumentos de plantilla para las colas y los descriptores.

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

Modo de uso

Define la interfaz AIDL que pasa el MQDescriptor al otro proceso. MQDescriptor se puede usar en cualquier lugar donde se pueda usar un objeto parcelable.

Los argumentos de plantilla obligatorios para MQDescriptor son el tipo de carga útil y la variante de la cola.

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

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

El proceso de configuración de cada lado de la cola de mensajes es casi idéntico a el proceso que usa HIDL, solo que usa los tipos de 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);

El proceso receptor crea el otro lado de la cola con el descriptor recibido de la interfaz 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()) {
   ...
}

El uso de AidlMessageQueue después de la configuración es el mismo que el de MessageQueue de HIDL. Todas las APIs que se describen en Usa MessageQueue son totalmente compatibles con AidlMessageQueue, con una excepción:

const MQDescriptor<T, flavor>* getDesc() se reemplaza por MQDescriptor<T, U> dupeDesc() , que muestra el MQDescriptor de AIDL.