No Android 12 e versões mais recentes, a Fila de mensagens rápidas (FMQ, na sigla em inglês) 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 do Binder após uma configuração rápida. O uso da AIDL estável permite a comunicação entre processos do sistema e do fornecedor.
Tipos de payload com suporte
FixedSizetipos da AIDLparcelable(não disponíveis no back-endcpp)- Tipos
unionda AIDL (não disponíveis no back-endcpp) - Tipos
enumda AIDL - Tipos integrais da AIDL
As mensagens enviadas entre processos na fila de mensagens de memória compartilhada precisam ter o mesmo layout de memória em limites de processos e não podem conter ponteiros. Tentar criar uma AidlMessageQueue com um tipo sem suporte causa um erro de compilação. Os tipos parcelable e union da AIDL no back-end cpp não podem ser usados com a Fila de mensagens rápidas porque herdam de android::Parcelable, que tem funções virtuais.
Tipos de fila com suporte
Os mesmos tipos de fila do HIDL, geralmente chamados de "sabores", têm suporte à AIDL. Eles são usados como argumentos de modelo para as filas e 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 transmite o MQDescriptor para o outro processo. MQDescriptor pode ser usado em qualquer lugar em que um parcelable possa estar.
Os argumentos de modelo necessá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 a o processo que usa 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 cria 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 a AidlMessageQueue após a configuração é o mesmo que usar a MessageQueue do HIDL.
Todas as APIs descritas em Usar a MessageQueue têm suporte total
à AidlMessageQueue com uma exceção:
const MQDescriptor<T, flavor>* getDesc() é substituído por
MQDescriptor<T, U> dupeDesc()
, que retorna a MQDescriptor da AIDL.