صف پیام سریع (FMQ)

زیرساخت فراخوانی رویه‌ای از دور (RPC) در HIDL از سازوکارهای binder استفاده می‌کند، یعنی فراخوانی‌ها سربار دارند، به عملیات هسته نیاز دارند، و می‌توانند عملکرد زمان‌بند را راه‌اندازی کنند. بااین‌حال، در مواردی که داده‌ها باید بین فرایندها با سربار کمتر و بدون دخالت هسته منتقل شوند، از سیستم «صف پیام سریع» (FMQ) استفاده می‌شود.

‫FMQ صف‌های پیام را با ویژگی‌های موردنظر ایجاد می‌کند. می‌توانید شیء MQDescriptorSync یا MQDescriptorUnsync را ازطریق تماس HIDL RPC ارسال کنید و فرایند دریافت‌کننده از این شیء برای دسترسی به صف پیام استفاده می‌کند.

انواع صف

‫Android از دو نوع صف (که به‌عنوان طعم شناخته می‌شوند) پشتیبانی می‌کند:

  • صف‌های همگام‌سازی‌نشده می‌توانند سرریز شوند و خوانندگان زیادی داشته باشند؛ هر خواننده باید داده‌ها را به‌موقع بخواند، درغیراین‌صورت آن‌ها را ازدست می‌دهد.
  • صف‌های همگام‌سازی‌شده مجاز به سرریز شدن نیستند و فقط می‌توانند یک خواننده داشته باشند.

هر دو نوع صف مجاز به سرریز شدن نیستند (خواندن از صف خالی ناموفق است) و فقط یک نویسنده می‌توانند داشته باشند.

صف‌های همگام‌سازی‌نشده

صف غیرهمگام‌سازی‌شده فقط یک نویسنده دارد، اما می‌تواند هر تعداد خواننده داشته باشد. یک موقعیت نوشتن برای صف وجود دارد؛ بااین‌حال، هر خواننده موقعیت خواندن مستقل خود را پیگیری می‌کند.

نوشتن در صف همیشه موفقیت‌آمیز است (سرریز بررسی نمی‌شود) تا زمانی که بزرگ‌تر از ظرفیت صف پیکربندی‌شده نباشند (نوشتن بزرگ‌تر از ظرفیت صف بلافاصله ناموفق می‌شود). ازآنجایی‌که هر خواننده ممکن است موقعیت خواندن متفاوتی داشته باشد، به‌جای اینکه منتظر بمانیم تا هر خواننده هر بخش از داده‌ها را بخواند، هرگاه نوشتارهای جدید به فضا نیاز داشته باشند، داده‌ها از صف خارج می‌شوند.

خوانندگان مسئول بازیابی داده‌ها قبل‌از اینکه از انتهای صف خارج شوند هستند. خواندن داده‌هایی که تلاش می‌کند داده‌های بیشتری از آنچه دردسترس است بخواند یا بلافاصله (اگر غیرمسدودکننده باشد) ناموفق می‌شود یا منتظر می‌ماند تا داده‌های کافی دردسترس قرار گیرد (اگر مسدودکننده باشد). درخواست خواندنی که تلاش می‌کند داده‌های بیشتری از ظرفیت صف بخواند، همیشه فوراً ناموفق می‌شود.

اگر خواننده‌ای نتواند با نویسنده همگام شود، به‌طوری‌که مقدار داده‌های نوشته‌شده و هنوز خوانده‌نشده توسط آن خواننده از ظرفیت صف فراتر رود، خواندن بعدی داده‌ای برنمی‌گرداند؛ درعوض، موقعیت خواندن خواننده را به موقعیت نوشتن به‌علاوه نصف ظرفیت بازنشانی می‌کند و سپس خطایی برمی‌گرداند. این کار باعث می‌شود نیمی از میان‌گیر برای خواندن دردسترس باشد و فضا برای نوشتن‌های جدید رزرو شود تا از سرریز شدن فوری مجدد صف جلوگیری شود. اگر داده‌های دردسترس برای خواندن پس‌از سرریز اما قبل‌از خواندن بعدی بررسی شود، داده‌های دردسترس بیشتری را برای خواندن نسبت‌به ظرفیت صف نشان می‌دهد که نشان‌دهنده وقوع سرریز است. (اگر صف بین بررسی داده‌های دردسترس و تلاش برای خواندن آن داده‌ها سرریز شود، تنها نشانه سرریز این است که خواندن ناموفق است.)

صف‌های همگام‌سازی‌شده

صف همگام‌سازی‌شده یک نویسنده و یک خواننده با یک موقعیت نوشتن و یک موقعیت خواندن دارد. نوشتن داده‌های بیشتر از فضای موجود در صف یا خواندن داده‌های بیشتر از آنچه درحال‌حاضر در صف وجود دارد غیرممکن است. بسته به اینکه تابع نوشتن یا خواندن مسدودکننده یا غیرمسدودکننده فراخوانی شده باشد، تلاش برای فراتر رفتن از فضای دردسترس یا داده‌ها یا بلافاصله با شکست مواجه می‌شود یا تا زمانی که عملیات موردنظر تکمیل شود مسدود می‌شود. تلاش برای خواندن یا نوشتن داده‌های بیشتر از ظرفیت صف همیشه فوراً ناموفق می‌شود.

راه‌اندازی FMQ

صف پیام به چندین شیء MessageQueue نیاز دارد: یکی برای نوشتن در آن، و یک یا چند شیء برای خواندن از آن. هیچ پیکربندی صریحی برای اینکه کدام شیء برای نوشتن یا خواندن استفاده شود وجود ندارد؛ کاربر مسئول است که اطمینان یابد هیچ شیء‌ای برای خواندن و نوشتن استفاده نمی‌شود، حداکثر یک نویسنده وجود دارد، و برای صف‌های همگام‌سازی‌شده، حداکثر یک خواننده وجود دارد.

ایجاد اولین شیء MessageQueue

صف پیام با یک تماس ایجاد و پیکربندی می‌شود:

#include <fmq/MessageQueue.h>
using android::hardware::kSynchronizedReadWrite;
using android::hardware::kUnsynchronizedWrite;
using android::hardware::MQDescriptorSync;
using android::hardware::MQDescriptorUnsync;
using android::hardware::MessageQueue;
....
// For a synchronized nonblocking FMQ
mFmqSynchronized =
  new (std::nothrow) MessageQueue<uint16_t, kSynchronizedReadWrite>
      (kNumElementsInQueue);
// For an unsynchronized FMQ that supports blocking
mFmqUnsynchronizedBlocking =
  new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
      (kNumElementsInQueue, true /* enable blocking operations */);
  • مقدارده اولیه MessageQueue<T, flavor>(numElements) شیئی را ایجاد و مقداردهی اولیه می‌کند که از عملکرد صف پیام پشتیبانی می‌کند.
  • مقداردهی اولیه MessageQueue<T, flavor>(numElements, configureEventFlagWord) شیئی را ایجاد و مقداردهی اولیه می‌کند که از عملکرد صف پیام با مسدود کردن پشتیبانی می‌کند.
  • flavor می‌تواند kSynchronizedReadWrite برای صف همگام‌سازی‌شده یا kUnsynchronizedWrite برای صف همگام‌سازی‌نشده باشد.
  • uint16_t (در این مثال) می‌تواند هر نوع تعریف‌شده با HIDL باشد که شامل بافرهای تودرتو (بدون انواع string یا vec نوع)، دسته‌ها، یا میان‌ها نباشد.
  • kNumElementsInQueue اندازه صف را براساس تعداد ورودی‌ها نشان می‌دهد؛ این مقدار اندازه میان‌گیر حافظه مشترک را که برای صف اختصاص داده شده است تعیین می‌کند.

ایجاد شیء دوم MessageQueue

سمت دوم صف پیام بااستفاده از شیء MQDescriptor که از سمت اول به‌دست آمده است ایجاد می‌شود. شیء MQDescriptor ازطریق فراخوانی HIDL یا AIDL RPC به فرایندی که انتهای دوم صف پیام را دربردارد ارسال می‌شود. ‫MQDescriptor حاوی اطلاعاتی درباره صف است، ازجمله:

  • اطلاعات مربوط به نگاشتن بافر و نوشتن اشاره‌گر.
  • اطلاعاتی برای نگاشت اشاره‌گر خواندن (اگر صف همگام‌سازی شده باشد).
  • اطلاعاتی برای نگاشت کلمه پرچم رویداد (اگر صف مسدودکننده باشد).
  • نوع شیء (<T, flavor>)، که شامل نوع تعریف‌شده با HIDL از عناصر صف و طعم صف (همگام‌سازی‌شده یا همگام‌سازی‌نشده) می‌شود.

می‌توانید از شیء MQDescriptor برای ساختن شیء MessageQueue استفاده کنید:

MessageQueue<T, flavor>::MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers)

پارامتر resetPointers نشان می‌دهد که آیا هنگام ایجاد این شیء MessageQueue، موقعیت‌های خواندن و نوشتن به ۰ بازنشانی شوند یا نه. در صف غیرهمگام‌سازی‌شده، موقعیت خواندن (که برای هر MessageQueue شیء در صف‌های غیرهمگام‌سازی‌شده محلی است) همیشه درطول ایجاد روی ۰ تنظیم می‌شود. معمولاً MQDescriptor درطول ایجاد اولین شیء صف پیام اولیه می‌شود. برای کنترل بیشتر بر حافظه مشترک، می‌توانید MQDescriptor را به‌صورت دستی تنظیم کنید (MQDescriptor در system/libhidl/base/include/hidl/MQDescriptor.h تعریف شده است)، سپس هر شیء MessageQueue را همان‌طور که در این بخش توضیح داده شده است ایجاد کنید.

مسدود کردن صف‌ها و پرچم‌های رویداد

به‌طور پیش‌فرض، صف‌ها از مسدودسازی خواندن و نوشتن پشتیبانی نمی‌کنند. دو نوع مسدود کردن تماس‌های خواندن و نوشتن وجود دارد:

  • کوته‌شکل، با سه پارامتر (اشاره‌گر داده، تعداد موارد، مهلت زمانی)، از مسدود کردن عملیات خواندن و نوشتن جداگانه در یک صف پشتیبانی می‌کند. هنگام استفاده از این فرم، صف پرچم رویداد و ماسک‌های بیت را داخلی مدیریت می‌کند، و اولین شیء صف پیام باید با پارامتر دوم true مقداردهی اولیه شود. برای مثال:
    // For an unsynchronized FMQ that supports blocking
    mFmqUnsynchronizedBlocking =
      new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
          (kNumElementsInQueue, true /* enable blocking operations */);
    
  • بلند، با شش پارامتر (شامل پرچم رویداد و ماسک‌های بیت)، از استفاده از شیء EventFlag مشترک بین چند صف پشتیبانی می‌کند و امکان تعیین ماسک‌های بیت اعلان را برای استفاده فراهم می‌کند. در این حالت، پرچم رویداد و ماسک‌های بیت باید به هر تماس خواندن و نوشتن ارائه شوند.

برای فرم بلند، می‌توانید EventFlag را به‌طور صریح در هر readBlocking() و writeBlocking() تماس ارائه دهید. می‌توانید یکی از صف‌ها را با پرچم رویداد داخلی مقداردهی اولیه کنید، که سپس باید بااستفاده از getEventFlagWord() از MessageQueue شیء آن صف استخراج شود و برای ایجاد EventFlag شیء در هر فرایند برای استفاده با FMQهای دیگر استفاده شود. یا می‌توانید اشیای EventFlag را با هر حافظه مشترک مناسبی مقداردهی اولیه کنید.

به‌طورکلی، هر صف باید فقط از یکی از موارد غیرمسدودکننده، مسدودکننده کوتاه، یا مسدودکننده بلند استفاده کند. ترکیب آن‌ها خطا نیست، اما برای رسیدن به نتیجه مطلوب، برنامه‌نویسی دقیق لازم است.

علامت‌گذاری حافظه به‌عنوان فقط خواندنی

به‌طور پیش‌فرض، حافظه مشترک اجازه خواندن و نوشتن دارد. برای صف‌های غیرهمگام‌سازی‌شده (kUnsynchronizedWrite)، ممکن است نویسنده بخواهد قبل‌از توزیع اشیای MQDescriptorUnsync، اجازه‌های نوشتن را برای همه خوانندگان بردارد. این کار تضمین می‌کند که فرایندهای دیگر نتوانند در صف بنویسند، که برای محافظت دربرابر اشکالات یا رفتار بد در فرایندهای خواننده توصیه می‌شود. اگر نویسنده می‌خواهد خوانندگان بتوانند هر زمان که از MQDescriptorUnsync برای ایجاد طرف خواندن صف استفاده می‌کنند، صف را بازنشانی کنند، حافظه نمی‌تواند به‌عنوان فقط خواندنی علامت‌گذاری شود. این رفتار پیش‌فرض سازنده MessageQueue است. بنابراین اگر کاربران فعلی برای این صف وجود داشته باشند، کد آن‌ها باید تغییر کند تا صف با resetPointer=false ساخته شود.

  • نویسنده: با توصیفگر فایل MQDescriptor با ashmem_set_prot_region تماس بگیرید و منطقه را روی فقط خواندنی (PROT_READ) تنظیم کنید:
    int res = ashmem_set_prot_region(mqDesc->handle->data[0], PROT_READ)
  • Reader: Create message queue with resetPointer=false (the default is true):
    mFmq = new (std::nothrow) MessageQueue(mqDesc, false);

استفاده از MessageQueue

میانای برنامه‌سازی کاربردی عمومی شیء MessageQueue عبارت است از:

size_t availableToWrite() // Space available (number of elements).
size_t availableToRead() // Number of elements available.
size_t getQuantumSize() // Size of type T in bytes.
size_t getQuantumCount() // Number of items of type T that fit in the FMQ.
bool isValid() // Whether the FMQ is configured correctly.
const MQDescriptor<T, flavor>* getDesc() // Return info to send to other process.

bool write(const T* data)  // Write one T to FMQ; true if successful.
bool write(const T* data, size_t count) // Write count T's; no partial writes.

bool read(T* data); // read one T from FMQ; true if successful.
bool read(T* data, size_t count); // Read count T's; no partial reads.

bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);

// Allows multiple queues to share a single event flag word
std::atomic<uint32_t>* getEventFlagWord();

bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
uint32_t writeNotification, int64_t timeOutNanos = 0,
android::hardware::EventFlag* evFlag = nullptr); // Blocking write operation for count Ts.

bool readBlocking(T* data, size_t count, uint32_t readNotification,
uint32_t writeNotification, int64_t timeOutNanos = 0,
android::hardware::EventFlag* evFlag = nullptr) // Blocking read operation for count Ts;

// APIs to allow zero copy read/write operations
bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
bool commitWrite(size_t nMessages);
bool beginRead(size_t nMessages, MemTransaction* memTx) const;
bool commitRead(size_t nMessages);

می‌توانید از availableToWrite() و availableToRead() برای تعیین میزان داده‌ای که در یک عملیات می‌تواند منتقل شود استفاده کنید. در صف همگام‌سازی‌نشده:

  • ‫availableToWrite() همیشه ظرفیت صف را برمی‌گرداند.
  • هر خواننده موقعیت خواندن خودش را دارد و محاسبات خودش را برای availableToRead() انجام می‌دهد.
  • از دیدگاه خواننده کند، صف می‌تواند سرریز شود؛ این امر می‌تواند منجر به این شود که availableToRead() مقداری بزرگ‌تر از اندازه صف برگرداند. اولین خواندن پس‌از اینکه سرریز ناموفق باشد و منجر به تنظیم موقعیت خواندن برای آن خواننده برابر با اشاره‌گر نوشتن فعلی شود، صرف‌نظر از اینکه سرریز ازطریق availableToRead() گزارش شده باشد یا نه.

اگر همه داده‌های درخواست‌شده بتواند به صف انتقال داده شود (و انتقال داده شود)، روش‌های read() و write() مقدار true را برمی‌گردانند. این روش‌ها مسدود نمی‌کنند؛ یا موفق می‌شوند (و true را برمی‌گردانند)، یا بلافاصله شکست (false) را برمی‌گردانند.

روش‌های readBlocking() و writeBlocking() منتظر می‌مانند تا عملیات درخواست‌شده تکمیل شود یا تا زمانی که زمان آن‌ها به‌پایان برسد (مقدار timeOutNanos صفر یعنی زمان آن‌ها هرگز به‌پایان نمی‌رسد).

عملیات مسدودسازی بااستفاده از کلمه پرچم رویداد اجرا می‌شود. به‌طور پیش‌فرض، هر صف کلمه پرچم خود را برای پشتیبانی از شکل کوتاه readBlocking() و writeBlocking() ایجاد و استفاده می‌کند. چندین صف می‌توانند یک کلمه را به‌اشتراک بگذارند، بنابراین یک فرایند می‌تواند برای نوشتن یا خواندن در هریک از صف‌ها منتظر بماند. با فراخوانی getEventFlagWord()، می‌توانید اشاره‌گری به کلمه پرچم رویداد صف دریافت کنید، و می‌توانید از آن اشاره‌گر (یا هر اشاره‌گر به مکان حافظه مشترک مناسب) برای ایجاد شیء EventFlag استفاده کنید تا به شکل طولانی readBlocking() و writeBlocking() برای صف دیگری منتقل شود. پارامترهای readNotification و writeNotification مشخص می‌کنند که از کدام بیت‌های پرچم رویداد باید برای نشان دادن خواندن و نوشتن در آن صف استفاده شود. ‫readNotification و writeNotification ماسک‌های بیتی ۳۲ بیتی هستند.

‫readBlocking() در writeNotification بیت منتظر می‌ماند؛ اگر این پارامتر ۰ باشد، تماس همیشه ناموفق خواهد بود. اگر مقدار readNotification صفر باشد، تماس ناموفق نخواهد بود، اما خواندن موفق هیچ‌یک از بیت‌های اعلان را تنظیم نخواهد کرد. در صف هم‌زمان‌سازی‌شده، این یعنی تماس writeBlocking() مربوطه هرگز بیدار نمی‌شود، مگراینکه بیت در جای دیگری تنظیم شده باشد. در صف غیرهمگام‌سازی‌شده، writeBlocking() منتظر نمی‌ماند (همچنان باید برای تنظیم بیت اعلان نوشتن استفاده شود)، و مناسب است که خواندن‌ها هیچ بیت اعلانی را تنظیم نکنند. به‌همین ترتیب، اگر readNotification صفر باشد، writeblocking() ناموفق خواهد بود، و نوشتن موفقیت‌آمیز بیت‌های writeNotification مشخص‌شده را تنظیم می‌کند.

برای انتظار در چند صف به‌طور هم‌زمان، از روش EventFlag شیء wait() برای انتظار در یک ماسک بیت اعلان‌ها استفاده کنید. روش wait() کلمه وضعیت را با بیت‌هایی که باعث بیدار شدن شده‌اند برمی‌گرداند. سپس از این اطلاعات برای درستی‌سنجی اینکه صف مربوطه فضای کافی یا داده‌های کافی برای عملیات نوشتن و خواندن موردنظر دارد استفاده می‌شود و write() و read() غیرمسدودکننده اجرا می‌شود. برای دریافت اعلان عملیات پست، از تماس دیگری با روش wake() شیء EventFlag استفاده کنید. برای تعریف EventFlag انتزاع، به system/libfmq/include/fmq/EventFlag.h مراجعه کنید.

عملیات کپی صفر

روش‌های read، write، readBlocking، و writeBlocking() اشاره‌گری به میان‌گیر ورودی-خروجی را به‌عنوان آرگومان می‌گیرند و از فراخوانی‌های memcpy() به‌صورت داخلی برای کپی کردن داده‌ها بین همان میان‌گیر و میان‌گیر حلقه‌ای FMQ استفاده می‌کنند. برای بهبود عملکرد، Android 8.0 و نسخه‌های بالاتر شامل مجموعه‌ای از واسط‌های برنامه‌نویسی کاربردی است که دسترسی مستقیم به اشاره‌گر در بافر حلقه را فراهم می‌کند و نیاز به استفاده از memcpy تماس را ازبین می‌برد.

از APIهای عمومی زیر برای عملیات FMQ بدون کپی استفاده کنید:

bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
bool commitWrite(size_t nMessages);

bool beginRead(size_t nMessages, MemTransaction* memTx) const;
bool commitRead(size_t nMessages);
  • روش beginWrite اشاره‌گرهای پایه را در میانگیر حلقه‌ای FMQ ارائه می‌دهد. پس‌از نوشتن داده‌ها، آن‌ها را بااستفاده از commitWrite() تعهد کنید. روش‌های beginRead و commitRead عملکرد یکسانی دارند.
  • روش‌های beginRead و Write تعداد پیام‌هایی را که باید خوانده و نوشته شود به‌عنوان ورودی می‌گیرند و مقدار بولی برمی‌گردانند که نشان می‌دهد خواندن یا نوشتن امکان‌پذیر است یا نه. اگر خواندن یا نوشتن امکان‌پذیر باشد، memTx struct با اشاره‌گرهای پایه‌ای پر می‌شود که می‌توان از آن‌ها برای دسترسی مستقیم اشاره‌گر به حافظه مشترک میان‌گیر حلقه‌ای استفاده کرد.
  • ساختار MemRegion حاوی جزئیاتی درباره بلوک حافظه است، ازجمله اشاره‌گر پایه (نشانی پایه بلوک حافظه) و طول برحسب T (طول بلوک حافظه برحسب نوع تعریف‌شده HIDL صف پیام).
  • ساختار MemTransaction شامل دو ساختار MemRegion است، first و second، زیرا خواندن یا نوشتن در بافر حلقوی ممکن است نیاز به پیچیدن به ابتدای صف داشته باشد. این به این معنی است که برای خواندن و نوشتن داده‌ها در بافر حلقه FMQ، به دو اشاره‌گر پایه نیاز است.

برای دریافت نشانی پایه و طول از ساختار MemRegion:

T* getAddress(); // gets the base address
size_t getLength(); // gets the length of the memory region in terms of T
size_t getLengthInBytes(); // gets the length of the memory region in bytes

برای دریافت ارجاع به اولین و دومین ساختار MemRegion در شیء MemTransaction:

const MemRegion& getFirstRegion(); // get a reference to the first MemRegion
const MemRegion& getSecondRegion(); // get a reference to the second MemRegion

مثال نوشتن در FMQ بااستفاده از میاناهای برنامه‌سازی کاربردی کپی صفر:

MessageQueueSync::MemTransaction tx;
if (mQueue->beginRead(dataLen, &tx)) {
    auto first = tx.getFirstRegion();
    auto second = tx.getSecondRegion();

    foo(first.getAddress(), first.getLength()); // method that performs the data write
    foo(second.getAddress(), second.getLength()); // method that performs the data write

    if(commitWrite(dataLen) == false) {
       // report error
    }
} else {
   // report error
}

روش‌های کمکی زیر نیز بخشی از MemTransaction است:

  • ‫T* getSlot(size_t idx); اشاره‌گری را به جایگاه idx در MemRegions که بخشی از این شیء MemTransaction است برمی‌گرداند. اگر شیء MemTransaction نشان‌دهنده مناطق حافظه برای خواندن و نوشتن N مورد از نوع T باشد، محدوده معتبر idx بین ۰ و N-1 است.
  • ‫bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1); nMessages مورد از نوع T را در ناحیه‌های حافظه شرح‌داده‌شده توسط شیء، از نمایه startIdx می‌نویسد. این روش از memcpy() استفاده می‌کند و برای عملیات بدون کپی درنظر گرفته نشده است. اگر شیء MemTransaction نشان‌دهنده حافظه برای خواندن و نوشتن N مورد از نوع T باشد، محدوده معتبر idx بین ۰ و N-۱ است.
  • ‫bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1); روش کمکی برای خواندن nMessages مورد از نوع T از مناطق حافظه توصیف‌شده توسط شیء شروع از startIdx است. این روش از memcpy() استفاده می‌کند و برای استفاده در عملیات کپی صفر درنظر گرفته نشده است.

ارسال صف ازطریق HIDL

در طرف ایجادکننده:

  1. همان‌طور که در بالا توضیح داده شد، یک شیء صف پیام ایجاد کنید.
  2. با isValid() درستی‌سنجی کنید که شیء معتبر باشد.
  3. اگر با گذراندن EventFlag به شکل طولانی readBlocking() یا writeBlocking() در چندین صف منتظر هستید، می‌توانید اشاره‌گر پرچم رویداد (بااستفاده از getEventFlagWord()) را از شیء MessageQueue که برای ایجاد پرچم مقداردهی اولیه شده است استخراج کنید و از آن پرچم برای ایجاد شیء EventFlag لازم استفاده کنید.
  4. از روش MessageQueue getDesc() برای دریافت شیء توصیف‌گر استفاده کنید.
  5. در فایل HAL، به این روش پارامتری از نوع fmq_sync یا fmq_unsync بدهید که در آن T نوع مناسب تعریف‌شده با HIDL است. از این برای ارسال شیء برگشتی از getDesc() به فرایند دریافت استفاده کنید.

در طرف دریافت‌کننده:

  1. از شیء توصیف‌کننده برای ایجاد شیء MessageQueue استفاده کنید. از طعم صف و نوع داده یکسانی استفاده کنید، درغیراین‌صورت الگو کامپایل نمی‌شود.
  2. اگر پرچم رویدادی را استخراج کردید، پرچم را از شیء MessageQueue مربوطه در فرایند دریافت استخراج کنید.
  3. برای انتقال داده‌ها از شیء MessageQueue استفاده کنید.