As of Android 12, Fast Message Queue can be used with AIDL interfaces using the NDK backend. This allows processes to communicate without the overhead and restrictions of binder transactions after some short setup. Using Stable AIDL allows communication between system and vendor processes.
Supported payload types
- @FixedSize AIDL
parcelable
types - AIDL
enum
types - AIDL integral types
The messages sent between processes in the shared memory message queue must have the same
memory layout across process boundaries and cannot contain pointers. Attempting to create an
AidlMessageQueue
with a type that isn't supported will cause a compilation error.
Supported queue types
The same queue types from HIDL, often called flavors, are supported with AIDL. These are used as template arguments for the queues and descriptors.
HIDL Types | AIDL Types |
---|---|
android::hardware::kSynchronizedReadWrite |
android.hardware.common.fmq.SynchronizedReadWrite |
android::hardware::kUnsynchronizedWrite |
android.hardware.common.fmq.UnsynchronizedWrite |
How to use
Define the AIDL interface that will pass the MQDescriptor
to the other process.
MQDescriptor
can be used anywhere a parcelable can be.
The required template arguments for MQDescriptor
are payload type and queue flavor.
import android.hardware.common.fmq.MQDescriptor
import android.hardware.common.fmq.SynchronizedReadWrite
void getQueue(out MQDescriptor<int, SynchronizedReadWrite> mqDesc);
The process of setting up each side of the message queue is nearly identical to the process using HIDL, just using the AIDL types.
#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);
The receiving process will create the other side of the queue with the descriptor received from the AIDL interface.
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()) {
...
}
Using the AidlMessageQueue
after setup is the same as the HIDL MessageQueue
.
All of the APIs described at Using the MessageQueue
are fully supported with AidlMessageQueue
with one exception:
const MQDescriptor<T, flavor>* getDesc()
is replaced by MQDescriptor<T, U> dupeDesc()
which returns the AIDL MQDescriptor
.