Fila de mensagens rápidas com AIDL

No Android 12, a Fila de mensagens rápidas pode ser usada com interfaces AIDL usando o back-end do NDK. Isso permite que os processos se comuniquem sem a sobrecarga e as restrições das transações de binder após uma configuração rápida. Usar a AIDL estável permite a comunicação entre processos do sistema e do fornecedor.

Tipos de payload compatíveis

As mensagens enviadas entre processos na fila de mensagens de memória compartilhada precisam ter o mesmo layout de memória em todos os limites de processo e não podem conter ponteiros. Tentar criar um AidlMessageQueue com um tipo sem suporte causa um erro de compilação.

Tipos de filas compatíveis

Os mesmos tipos de fila do HIDL, geralmente chamados de variantes, são compatíveis com a AIDL. Eles são usados como argumentos de modelo para as filas e os descritores.

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

Como usar

Defina a interface AIDL que vai transmitir o MQDescriptor para o outro processo. MQDescriptor pode ser usado em qualquer lugar em que um parcelable possa ser usado.

Os argumentos de modelo obrigatórios para MQDescriptor são o tipo de payload e o sabor da fila.

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

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

O processo de configuração de cada lado da fila de mensagens é quase idêntico ao processo usando HIDL, apenas usando os tipos 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);

O processo de recebimento vai criar o outro lado da fila com o descritor recebido da interface 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()) {
   ...
}

Usar o AidlMessageQueue após a configuração é o mesmo que o HIDL MessageQueue. Todas as APIs descritas em Usar o MessageQueue são totalmente compatíveis com AidlMessageQueue, com uma exceção:

const MQDescriptor<T, flavor>* getDesc() foi substituído por MQDescriptor<T, U> dupeDesc() que retorna o AIDL MQDescriptor.