تستخدم البنية الأساسية لاستدعاء الإجراءات عن بُعد (RPC) في HIDL آليات الربط، مما يعني أن الاتصالات تتضمن عبء زائد، وتتطلب عمليات kernel، ويمكنها تشغيل إجراء الجدولة. ومع ذلك، في الحالات التي يجب فيها نقل البيانات بين العمليات مع تقليل الوقت المستغرَق في عمليات المعالجة الثانوية وعدم تدخل النواة، يتم استخدام نظام "قائمة الرسائل السريعة" (FMQ).
تُنشئ واجهة FMQ قوائم انتظار الرسائل باستخدام السمات المطلوبة. يمكنك إرسال كائن
MQDescriptorSync
أو MQDescriptorUnsync
عبر استدعاء HIDL RPC، وتستخدم عملية الاستلام للوصول إلى
قائمة انتظار الرسائل.
أنواع قوائم الانتظار
يتيح Android نوعَين من قوائم الانتظار (المعروفَين باسم النُسخ):
- يُسمح بتجاوز سعة قوائم الانتظار غير المتزامنة، ويمكن أن تتضمّن العديد من القارئين، ويجب أن يقرأ كل قارئ البيانات في الوقت المناسب وإلا سيفقدها.
- لا يُسمح بتجاوز سعة قوائم الانتظار المتزامنة، ويمكن أن يكون لها قارِئ واحد فقط.
لا يُسمح لكلا النوعين من قوائم الانتظار بمواصلة العمل (تفشل القراءة من قائمة انتظار فارغة) ويمكن أن يكون لكاتب واحد فقط.
قوائم الانتظار غير المتزامنة
تحتوي "القائمة الانتظار غير المتزامنة" على كاتب واحد فقط، ولكن يمكن أن تحتوي على أي عدد من القارئين. هناك موضع كتابة واحد للانتظار، ومع ذلك، يحتفظ كل قارئ بموضع القراءة المستقل الخاص به.
تنجح عمليات الكتابة إلى "القائمة الانتظار" دائمًا (لا يتم التحقّق من حدوث تدفّق زائد) ما دام حجمها ليس أكبر من سعة "القائمة الانتظار" التي تم ضبطها (تتعطّل عمليات الكتابة التي تزيد عن سعة "القائمة الانتظار" على الفور). وبما أنّ كل قارئ قد يكون لديه موضع قراءة مختلف، بدلاً من الانتظار إلى أن يقرأ كل قارئ كل قطعة من البيانات، يتمّ إزالة البيانات من "قائمة الانتظار" كلما احتجت عمليات الكتابة الجديدة إلى المساحة.
القراء هم مسئولون عن استرداد البيانات قبل أن تنزل عن نهاية قائمة الانتظار. يتعذّر على القراءة التي تحاول قراءة بيانات أكثر من المتاحة إما على الفور (إذا كانت غير محظورة) أو تنتظر توفُّر بيانات كافية (في حال الحظر). فدائمًا ما تخفق القراءة التي تحاول قراءة بيانات أكثر من سعة قائمة الانتظار على الفور.
إذا فشل القارئ في متابعة الكاتب، بحيث أصبح مقدار البيانات التي كتبها ولم يقرأها ذلك القارئ بعد أكبر من سعة قائمة الانتظار، فإن القراءة التالية لا تعرض أي بيانات، وإنما يعيد تعيين موضع القراءة للقارئ ليعادل آخر موضع كتابة ثم يعرض الفشل. إذا تم التحقّق من البيانات المتاحة للقراءة بعد حدوث تدفّق زائد ولكن قبل القراءة التالية، فإنه يعرض بيانات أكثر متاحة للقراءة من سعة الانتظار، ما يشير إلى حدوث تدفّق زائد. (إذا امتلأت قائمة الانتظار بين التحقّق من البيانات المتاحة ومحاولة قراءة هذه البيانات، فإنّ المؤشر الوحيد على الامتلاء هو تعذُّر قراءة البيانات).
قوائم الانتظار المتزامنة
تحتوي "القائمة الانتظار المتزامنة" على كاتب واحد وقارئ واحد مع موضع كتابة واحد وموضع قراءة واحد. من المستحيل كتابة بيانات أكثر مما يمكن أن تستوعبه الطابور أو قراءة بيانات أكثر مما يحتوي عليه حاليًا. استنادًا إلى ما إذا تم استدعاء دالة القراءة أو الكتابة المحظورة أو غير المحظورة، تؤدي محاولات تجاوز المساحة أو البيانات المتاحة إلى تعذُّر الإجراء أو حظره إلى أن يتم إكمال العملية المطلوبة. إنّ محاولات قراءة أو كتابة بيانات أكثر من سعة الانتظار تفشل دائمًا على الفور.
إعداد طلب معلومات فورية
تتطلّب قائمة الرسائل الواردة عناصر MessageQueue
متعددة: عنصر واحد لكتابة الرسائل فيه وعنصر واحد أو أكثر لقراءتها. لا تتوفّر عملية برمجة صريحة لتحديد العنصر الذي يتم استخدامه للكتابة أو القراءة، ويتحمل المستخدم مسؤولية التأكّد من عدم استخدام أي عنصر للقراءة والكتابة معًا، ومن توفّر كاتب واحد على الأكثر، ومن توفّر قارئ واحد على الأكثر في الطوابير المتزامنة.
إنشاء أول كائن Messageplaylist
يتم إنشاء قائمة انتظار للرسائل وضبطها من خلال مكالمة واحدة:
#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)
initializer عنصرًا يتيح وظيفة "قائمة انتظار الرسائل" ويُنشئها. - ينشئ برنامج تهيئة
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
إلى ما إذا كان يجب إعادة ضبط مواضع القراءة
والكتابة على 0 أثناء إنشاء عنصر MessageQueue
هذا.
في قائمة الانتظار غير المتزامنة، يتم دائمًا ضبط موضع القراءة (الذي يكون محليًا لكل كائن
MessageQueue
في قوائم الانتظار غير المتزامنة) على 0
أثناء الإنشاء. عادةً ما يتمّ إعداد 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()
. يمكنك بدء إحدى
القوائم باستخدام علامة حدث داخلية، والتي يجب بعد ذلك
استخراجها من كائنات MessageQueue
الخاصة بهذه القائمة باستخدام
getEventFlagWord()
واستخدامها لإنشاء كائنات EventFlag
في كل عملية لاستخدامها مع قوائم FMQ الأخرى. بدلاً من ذلك، يمكنك بدء عناصر
EventFlag
باستخدام أي ذاكرة مشترَكة مناسبة.
بشكل عام، يجب أن تستخدم كل قائمة انتظار طريقة واحدة فقط من بين الحظر غير المشروط أو حظر المحتوى القصير أو حظر المحتوى الطويل. ولا يشكّل خلطهما خطأ، ولكن يجب برمجة المحتوى بعناية للحصول على النتيجة المطلوبة.
وضع علامة "للقراءة فقط" على الذاكرة
تمتلك الذاكرة المشتركة أذونات القراءة والكتابة تلقائيًا. بالنسبة إلى طوابير الرسائل غير المتزامنة (kUnsynchronizedWrite
)، قد يريد الكاتب إزالة أذونات الكتابة لجميع
القراء قبل توزيع عناصر MQDescriptorUnsync
. يضمن ذلك عدم تمكّن العمليات الأخرى
من الكتابة في "قائمة الانتظار"، وهو إجراء يُنصح به للحماية من الأخطاء أو السلوك السيئ في
عمليات القراءة.
إذا أراد الكاتب أن يتمكّن القرّاء من إعادة ضبط "القائمة الانتظار" كلما استخدموا
MQDescriptorUnsync
لإنشاء جانب القراءة من "القائمة الانتظار"، لا يمكن وضع علامة على الذاكرة
بصفتها للقراءة فقط. وهذا هو السلوك التلقائي للدالة الإنشائية MessageQueue
. وبالتالي، إذا كان هناك مستخدمون حاليون في قائمة الانتظار هذه، يجب تغيير الرمز الخاص بهم لإنشاء قائمة المحتوى التالي باستخدام resetPointer=false
.
- الكاتب: استدعاء
ashmem_set_prot_region
باستخدام وصف ملفMQDescriptor
والمنطقة التي تم ضبطها على القراءة فقط (PROT_READ
):int res = ashmem_set_prot_region(mqDesc->handle->data[0], PROT_READ)
- القارئ: إنشاء قائمة انتظار رسائل باستخدام
resetPointer=false
(القيمة التلقائية هي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
0 عدم انتهاء المهلة مطلقًا).
يتم تنفيذ عمليات الحظر باستخدام كلمة علامة حدث. بشكلٍ تلقائي،
تُنشئ كل قائمة انتظار كلمة علامة خاصة بها وتستخدمها للسماح بالشكل المختصر من
readBlocking()
وwriteBlocking()
. يمكن أن تشترك قوائم الانتظار المتعددة في كلمة واحدة، بحيث يمكن للعملية انتظار الكتابة أو القراءة في أي من قوائم الانتظار. عند استدعاء getEventFlagWord()
، يمكنك الحصول على مؤشر
لكلمة علامة حدث في إحدى القوائم، ويمكنك استخدام هذا المؤشر (أو أي
مؤشر إلى موقع مناسب للذاكرة) لإنشاء كائن
EventFlag
لتمريره إلى الشكل الطويل من
readBlocking()
وwriteBlocking()
لقائمة انتظار مختلفة. تُحدِّد المَعلمتَان readNotification
وwriteNotification
البتّات التي يجب استخدامها في علامة الحدث للإشارة إلى عمليات القراءة
والكتابة في هذه الطابور. readNotification
و
writeNotification
هما قناع بت 32 بت.
ينتظر readBlocking()
على writeNotification
بت،
إذا كانت هذه المَعلمة هي 0، يتعذّر دائمًا إجراء الاستدعاء. إذا كانت قيمة
readNotification
هي 0، لن تنجح عملية الاستدعاء،
ولكن لن تؤدي القراءة الناجحة إلى ضبط أي وحدات بت للإشعارات. في قائمة الانتظار المتزامنة،
يعني ذلك أنّ طلب writeBlocking()
المقابل لن يتم تفعيله أبدًا ما لم يتم ضبط القيمة في مكان آخر. في قائمة الانتظار غير المتزامنة، لا ينتظر writeBlocking()
(يجب أن يظلّ قيد الاستخدام لضبط وبت إشعار القيد)، ومن المناسب ألا تضبط عمليات القراءة أي وبت إشعار. وبالمثل، يتعذّر تنفيذ writeblocking()
إذا كانت قيمة
readNotification
هي 0، ويؤدي الإجراء الناجح إلى ضبط وحدات البت المحدّدة
writeNotification
.
للانتظار في قوائم انتظار متعددة في الوقت نفسه، استخدِم طريقة
wait()
في كائن EventFlag
للانتظار في قناع بتات للإشعارات. تُرجع الطريقة wait()
كلمة حالة تحتوي على وحدات البت التي تسببت في مجموعة التنشيط. وتُستخدَم هذه المعلومات بعد ذلك للتحقّق من توفّر
مساحة أو بيانات كافية في "القائمة الانتظار" المقابلة لإجراء عملية القراءة والكتابة المطلوبة وتنفيذ write()
وread()
غير المحظورة. لتلقي إشعار بعملية النشر، يمكنك استخدام استدعاء آخر لطريقة wake()
لكائن EventFlag
. للحصول على تعريف للتجريد EventFlag
،
راجع system/libfmq/include/fmq/EventFlag.h
.
عمليات النسخ بدون أي تكلفة
توجّه الطرق
read
وwrite
وreadBlocking
وwriteBlocking()
مؤشرًا إلى مخزن مؤقت للإدخال والإخراج كوسيطة وتستخدم
طلبات memcpy()
داخليًا لنسخ البيانات بين المخزن المؤقت نفسه والمخزن المؤقت لحلقة FMQ. لتحسين الأداء، يتضمّن الإصدار 8.0 من نظام التشغيل Android والإصدارات الأحدث مجموعة من واجهتَي برمجة التطبيقات (API) اللتين توفّران إمكانية وصول المؤشر مباشرةً إلى المخزن الدائري، ما يزيل الحاجة إلى استخدام طلبات memcpy
.
استخدِم واجهات برمجة التطبيقات العامة التالية لإجراء عمليات "الطلبات المجمّعة بدون نسخ":
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
البنية بمؤشرات أساسية يمكن استخدامها للوصول المباشر باستخدام المؤشر إلى الذاكرة المشتركة للوسيط الدائري. - يحتوي عنصر
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
بين 0 وN-1. - يكتب
bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
nMessages
عنصرًا من النوعT
في مناطق الذاكرة التي يصفّها العنصر، بدءًا من الفهرسstartIdx
. تستخدم هذه الطريقةmemcpy()
، وليست مصممة بغرض استخدامها. إذا كان عنصرMemTransaction
يمثّل ذاكرة لقراءة وكتابة N عنصر من النوعT
، يكون النطاق الصالح لـidx
بين 0 وN-1. bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
هي طريقة مساعدة لقراءةnMessages
عنصر من النوعT
من مناطق الذاكرة التي يصفها الكائن بدءًا منstartIdx
. تستخدِم هذه المحاولةmemcpy()
ولا يُقصد استخدامها في عملية بدون نسخة.
إرسال قائمة المحتوى التالي عبر HIDL
من جانب الإنشاء:
- أنشئ عنصرًا في "قائمة انتظار الرسائل" كما هو موضّح أعلاه.
- تحقَّق من صلاحية العنصر من خلال
isValid()
. - إذا كنت في انتظار قوائم انتظار متعددة من خلال تمرير
EventFlag
إلى الشكل الطويل منreadBlocking()
أوwriteBlocking()
، يمكنك استخراج مُشير علامة الحدث (باستخدامgetEventFlagWord()
) من ملف برمجيMessageQueue
تم إعداده لإنشاء العلامة، و استخدام هذه العلامة لإنشاء ملف برمجيEventFlag
ضروري. - استخدِم الطريقة
MessageQueue
getDesc()
للحصول على ملف تعريف. - في ملف HAL، امنح الطريقة مَعلمة من النوع
fmq_sync
أوfmq_unsync
حيث يكونT
هو نوع مناسب محدّد من HIDL. يمكنك استخدامه لإرسال العنصر الذي تم إرجاعه من خلال "getDesc()
" إلى عملية الاستلام.
على الجانب المستلِم:
- استخدِم كائن الوصف لإنشاء كائن
MessageQueue
. استخدِم نوع البيانات ونكهة "القائمة الانتظار" نفسها، وإلا لن يتم compiling (تجميع) النموذج. - إذا استخرجت علامة حدث، استخرِج العلامة من عنصر
MessageQueue
المقابل في عملية الاستقبال. - استخدِم عنصر
MessageQueue
لنقل البيانات.