Начиная с Android 12, Fast Message Queue можно использовать с интерфейсами AIDL, используя бэкенд NDK. Это позволяет процессам взаимодействовать без накладных расходов и ограничений, связанных с транзакциями Binder, после короткой настройки. Использование стабильной версии AIDL позволяет осуществлять связь между системными процессами и процессами сторонних разработчиков.
Поддерживаемые типы полезной нагрузки
- Типы AIDL
FixedSizeparcelable(недоступны в бэкендеcpp). -
unionтипов AIDL (недоступны в бэкендеcpp) - Типы
enumAIDL - интегральные типы AIDL
Сообщения, передаваемые между процессами в очереди сообщений, разделяемой памятью, должны иметь одинаковую структуру памяти на разных этапах процесса и не могут содержать указатели. Попытка создать AidlMessageQueue с неподдерживаемым типом приводит к ошибке компиляции. Типы AIDL parcelable и union в бэкенде cpp нельзя использовать с Fast Message Queue, поскольку они наследуются от android::Parcelable , который имеет виртуальные функции.
Поддерживаемые типы очередей
В AIDL поддерживаются те же типы очередей , что и в HIDL, часто называемые «вариантами». Они используются в качестве аргументов шаблона для очередей и дескрипторов.
| Типы HIDL | Типы AIDL |
|---|---|
android::hardware::kSynchronizedReadWrite | android.hardware.common.fmq.SynchronizedReadWrite |
android::hardware::kUnsynchronizedWrite | android.hardware.common.fmq.UnsynchronizedWrite |
Как использовать
Определите интерфейс AIDL, который передает MQDescriptor другому процессу. MQDescriptor можно использовать везде, где можно использовать Parcelable.
Обязательными аргументами шаблона для MQDescriptor являются тип полезной нагрузки и тип очереди.
import android.hardware.common.fmq.MQDescriptor
import android.hardware.common.fmq.SynchronizedReadWrite
void getQueue(out MQDescriptor<int, SynchronizedReadWrite> mqDesc);
Процесс настройки каждой стороны очереди сообщений практически идентичен процессу с использованием HIDL , только используются типы 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);
Процесс приема формирует другую сторону очереди с дескриптором, полученным от интерфейса 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()) {
...
}
Использование AidlMessageQueue после настройки аналогично использованию HIDL MessageQueue . Все API, описанные в разделе «Использование MessageQueue», полностью поддерживаются AidlMessageQueue , за одним исключением:
const MQDescriptor<T, flavor>* getDesc() заменяется на ` MQDescriptor<T, U> dupeDesc() , которая возвращает объект AIDL MQDescriptor .