คิวข้อความด่วน (FMQ)

หากต้องการการสนับสนุนเกี่ยวกับ AIDL โปรดดูข้อมูลเพิ่มเติมที่นี่ FMQ พร้อม AIDL

โครงสร้างพื้นฐานของการเรียกใช้โพรซีเยอร์ระยะไกล (RPC) ของ HIDL ใช้กลไกของ Binder ซึ่งหมายถึงการเรียกใช้มีค่าใช้จ่าย ต้องมีการดำเนินการเคอร์เนล และอาจทริกเกอร์ การทำงานของเครื่องจัดตารางเวลา อย่างไรก็ตาม ในกรณีที่ต้องโอนข้อมูลระหว่าง กระบวนการที่มีโอเวอร์เฮดน้อยกว่าและไม่เกี่ยวข้องกับเคอร์เนล คิวข้อความแบบรวดเร็ว ใช้ระบบ (FMQ)

FMQ สร้างคิวข้อความด้วยคุณสมบัติที่ต้องการ CANNOT TRANSLATE MQDescriptorSync หรือ MQDescriptorUnsync ออบเจ็กต์ก็ได้ ที่ส่งผ่านการเรียกใช้ HIDL RPC และใช้โดยกระบวนการรับเพื่อเข้าถึง คิวข้อความ

คิวข้อความด่วนรองรับเฉพาะใน C++ และในอุปกรณ์ ที่ใช้ Android 8.0 ขึ้นไป

ประเภท MessageQueue

Android รองรับคิว 2 ประเภท (เรียกว่ารสชาติ) ดังนี้

  • คิวที่ไม่ซิงค์จะมีจำนวนต่อได้ และอาจมีหลายรายการ ผู้อ่าน; ผู้อ่านแต่ละคนต้องอ่านข้อมูลให้ทันเวลาหรือสูญหาย
  • ไม่สามารถทำให้คิวข้อมูลตรงกัน เพิ่มได้ และจะมีได้เฉพาะคิว ผู้อ่าน 1 คน

ไม่อนุญาตให้จัดคิวทั้ง 2 ประเภทให้น้อยเกินไป (อ่านจากคิวว่าง ล้มเหลว) และมีผู้เขียนได้เพียงคนเดียว

ไม่ซิงค์แล้ว

คิวที่ไม่ได้ซิงค์จะมีผู้เขียนเพียง 1 คน แต่สามารถมีจำนวนกี่เพลงก็ได้ ผู้อ่าน คิวจะมีตำแหน่งการเขียน 1 ตำแหน่ง แต่ผู้อ่านแต่ละคน ติดตามตำแหน่งการอ่านอิสระ

การเขียนไปยังคิวจะสำเร็จเสมอ (ไม่ต้องทำเครื่องหมายสำหรับส่วนเกิน) ตราบใดที่ ไม่ใหญ่เกินความจุของคิวที่กำหนดค่าไว้ (เขียนที่ใหญ่กว่า ความจุของคิวล้มเหลวทันที) เนื่องจากผู้อ่านแต่ละคนอาจมีการอ่านที่ต่างกัน ของคุณ แทนที่จะต้องรอให้ผู้อ่านทุกคนอ่านข้อมูลทั้งหมด ได้รับอนุญาตให้หลุดออกจากคิวเมื่อใดก็ตามที่การเขียนใหม่จำเป็นต้องใช้ช่องว่าง

ผู้อ่านมีหน้าที่รับผิดชอบในการดึงข้อมูลก่อนที่จะตกเป็นเป้าหมายของ คิว การอ่านที่พยายามอ่านข้อมูลมากกว่าที่มีอยู่ ล้มเหลวทันที (หากไม่บล็อก) หรือรอให้มีข้อมูลมากพอ (หาก การบล็อก) การอ่านที่พยายามอ่านข้อมูลมากกว่าความจุของคิวอยู่เสมอ จะล้มเหลวทันที

ถ้าผู้อ่านตามผู้เขียนไม่ทัน ดังนั้นจำนวนข้อมูล ที่เขียนแล้ว แต่ผู้อ่านรายดังกล่าวยังไม่ได้อ่านมีปริมาณมากกว่า ความจุของคิว การอ่านถัดไปไม่แสดงข้อมูล แต่จะรีเซ็ตการอ่านของผู้อ่าน ตำแหน่งใหม่ให้เท่ากับตำแหน่งการเขียนล่าสุดแสดงว่าล้มเหลว หาก ข้อมูลที่อ่านได้จะถูกทำเครื่องหมายหลังจากรายการเพิ่มเติม แต่ก่อนที่จะอ่านครั้งถัดไป แสดงข้อมูลที่อ่านได้มากกว่าความจุคิว ซึ่งบ่งชี้ว่า เกิดการดำเนินการเพิ่มเติม (หากคิวเกิดการล้นระหว่างการตรวจสอบข้อมูลที่มีอยู่ และพยายามอ่านข้อมูลนั้น สิ่งเดียวที่บ่งชี้ถึงข้อมูลล้นก็คือ อ่านไม่สำเร็จ)

ผู้อ่านคิวที่ไม่ได้ซิงค์มักไม่ต้องการรีเซ็ต การอ่านและเขียนของคิว ดังนั้น เมื่อสร้างคิวจาก ผู้อ่านข้อบ่งชี้ควรใช้อาร์กิวเมนต์ "false" สำหรับ "resetPointers" พารามิเตอร์

ซิงค์แล้ว

คิวที่ซิงค์จะมีผู้เขียน 1 คนและผู้อ่าน 1 คนที่มีการเขียนครั้งเดียว และตำแหน่งการอ่านตำแหน่งเดียว เป็นไปไม่ได้ที่จะเขียนข้อมูลมากกว่า คิวมีพื้นที่สำหรับหรืออ่านข้อมูลมากกว่าที่คิวถูกระงับไว้ ขึ้นอยู่กับว่าฟังก์ชันการเขียนหรืออ่านการบล็อกหรือแบบไม่บล็อก เรียกใช้ มีความพยายามใช้พื้นที่เก็บข้อมูลเกินพื้นที่หรือข้อมูลอาจแสดงผลล้มเหลว ทันทีหรือบล็อกจนกว่าการดำเนินการที่ต้องการจะเสร็จสมบูรณ์ ความพยายามที่จะ อ่านหรือเขียนข้อมูลมากกว่าความจุคิวมักจะล้มเหลวทันที

ตั้งค่า FMQ

คิวข้อความต้องใช้ออบเจ็กต์ MessageQueue หลายรายการ ดังนี้ 1 ถึง และอย่างน้อย 1 แห่งให้อ่านได้ ไม่มีเนื้อหาที่ชัดเจน การกำหนดค่าว่าจะใช้ออบเจ็กต์ใดสำหรับการเขียนหรืออ่าน ก็ขึ้นอยู่กับ เพื่อให้มั่นใจว่าไม่มีการใช้ออบเจ็กต์ทั้งสำหรับการอ่านและการเขียน มีผู้เขียนได้สูงสุด 1 คน และสำหรับคิวที่ซิงค์ มีผู้เขียนได้สูงสุด 1 คน ผู้อ่าน

สร้างออบเจ็กต์ 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 non-blocking 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 รายการที่ 2

ด้านที่ 2 ของคิวข้อความจะสร้างโดยใช้ 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 ทั้งหมดตามที่อธิบายไว้ในส่วนนี้

บล็อกคิวและแฟล็กเหตุการณ์

โดยค่าเริ่มต้น คิวจะไม่รองรับการบล็อกการอ่าน/เขียน มี 2 ชนิด ของการบล็อกการเรียกอ่าน/เขียน:

  • รูปแบบสั้นที่มีพารามิเตอร์ 3 ตัว (ตัวชี้ข้อมูล จำนวนรายการ หมดเวลา) รองรับการบล็อกในการดำเนินการอ่าน/เขียนแต่ละรายการใน คิว เมื่อใช้แบบฟอร์มนี้ คิวจะจัดการแฟล็กเหตุการณ์และบิตมาสก์ ภายใน และออบเจ็กต์คิวข้อความแรกจะต้อง เริ่มต้นด้วยพารามิเตอร์ที่สองเป็น true ดังตัวอย่างต่อไปนี้
    // For an unsynchronized FMQ that supports blocking
    mFmqUnsynchronizedBlocking =
      new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>
          (kNumElementsInQueue, true /* enable blocking operations */);
    
  • วิดีโอแบบยาว มีพารามิเตอร์ 6 รายการ (รวมถึง Flag เหตุการณ์และบิตมาสก์) รองรับการใช้ออบเจ็กต์ EventFlag ที่แชร์ระหว่างหลายคิว และอนุญาตให้ระบุมาสก์บิตการแจ้งเตือนที่จะใช้ได้ ในกรณีนี้ ค่า ต้องระบุแฟล็กเหตุการณ์และบิตมาสก์ให้กับการเรียกใช้การอ่านและเขียนแต่ละครั้ง

สำหรับวิดีโอแบบยาว สามารถระบุ EventFlag อย่างชัดแจ้งใน การโทร readBlocking() และ writeBlocking() แต่ละครั้ง หนึ่งใน อาจเริ่มต้นคิวด้วยแฟล็กเหตุการณ์ภายใน ซึ่งต้อง ดึงข้อมูลจากออบเจ็กต์ MessageQueue ของคิวโดยใช้ getEventFlagWord()และใช้เพื่อสร้างEventFlag ในแต่ละกระบวนการเพื่อใช้กับ FMQ อื่นๆ อีกวิธีหนึ่งคือ สามารถเริ่มต้น EventFlag ออบเจ็กต์ด้วยการแชร์ที่เหมาะสมรายการใดก็ได้ ความทรงจำ

โดยทั่วไป แต่ละคิวควรใช้รูปแบบสั้นๆ แบบไม่บล็อกเพียง 1 รายการเท่านั้น การบล็อก หรือการบล็อก ในวิดีโอแบบยาว ไม่ใช่ข้อผิดพลาดที่จะผสมปนเปกัน แต่โปรดระวัง จะต้องเขียนโปรแกรมเพื่อให้ได้ผลลัพธ์ที่ต้องการ

ทำเครื่องหมายความทรงจำว่าอ่านอย่างเดียว

โดยค่าเริ่มต้น หน่วยความจำที่ใช้ร่วมกันจะมีสิทธิ์อ่านและเขียน สำหรับกรณีที่ไม่ซิงค์ คิว (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)
  • Reader: สร้างคิวข้อความด้วย resetPointer=false (the ค่าเริ่มต้นคือ true):
    mFmq = new (std::nothrow) MessageQueue(mqDesc, false);

ใช้ MessageQueue

API สาธารณะของออบเจ็กต์ 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 บิต

หากต้องการรอหลายคิวพร้อมกัน ให้ใช้ออบเจ็กต์ EventFlag wait() เพื่อรอการแจ้งเตือนเล็กน้อย เมธอด wait() จะแสดงข้อความสถานะพร้อมด้วยบิตที่ทำให้เกิดข้อผิดพลาด ก็ตื่นได้แล้ว จากนั้นระบบจะใช้ข้อมูลนี้เพื่อยืนยันคิวที่เกี่ยวข้อง มีพื้นที่ว่างเพียงพอหรือข้อมูลสำหรับการดำเนินการเขียน/อ่านที่ต้องการและดำเนินการ ไม่บล็อก write()/read() รับการดำเนินการโหลด ใช้การโทรอีกครั้งไปยัง EventFlag wake() สำหรับคำจำกัดความของ EventFlag แอบสแตรกชัน, หมายถึง system/libfmq/include/fmq/EventFlag.h.

ไม่มีการทำสำเนา

write/read/readBlocking/writeBlocking() API จะนำตัวชี้ไปยังบัฟเฟอร์อินพุต/เอาต์พุตเป็นอาร์กิวเมนต์และใช้ memcpy() โทรภายในเพื่อคัดลอกข้อมูลระหว่าง บัฟเฟอร์ริง FMQ เพื่อปรับปรุงประสิทธิภาพ Android 8.0 ขึ้นไปจะมีชุด API ที่มอบการเข้าถึงตัวชี้โดยตรงในบัฟเฟอร์ริง ทำให้ไม่ต้องใช้ฟังก์ชัน ต้องใช้การโทร 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 โครงสร้างนั้นสร้างขึ้นด้วยตัวชี้ฐานที่สามารถใช้เป็นตัวชี้โดยตรง เข้าถึงหน่วยความจำที่ใช้ร่วมกันของบัฟเฟอร์ริง
  • โครงสร้าง MemRegion มีรายละเอียดเกี่ยวกับบล็อกหน่วยความจำ รวมถึงตัวชี้ฐาน (ที่อยู่ฐานของบล็อกหน่วยความจำ) และความยาวใน พจน์ของ T (ความยาวของบล็อกหน่วยความจำตามที่กำหนดโดย HIDL ของคิวข้อความ)
  • โครงสร้าง MemTransaction มี MemRegion 2 รายการ first และ second เป็นการอ่านหรือเขียนลงใน บัฟเฟอร์ริงอาจต้องตัดรอบไปยังตอนต้นของคิว ช่วงเวลานี้ หมายความว่าจะต้องใช้ตัวชี้พื้นฐาน 2 ตัวเพื่ออ่าน/เขียนข้อมูลลงใน 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 โดยใช้ API การคัดลอกเป็นศูนย์

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);
    เขียนรายการประเภท T nMessages รายการลงในภูมิภาคหน่วยความจำ อธิบายโดยออบเจ็กต์ เริ่มต้นจากดัชนี startIdx วิธีนี้ ใช้ memcpy() และไม่ได้มีไว้เพื่อใช้สำหรับการทำสำเนา การดำเนินการ หากออบเจ็กต์ MemTransaction แสดงหน่วยความจำต่อ อ่าน/เขียน N รายการประเภท T ช่วงที่ถูกต้องคือ idx ระหว่าง 0 ถึง N-1
  • bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
    เมธอดตัวช่วยในการอ่าน nMessages รายการในประเภท T จาก ภูมิภาคหน่วยความจำที่อธิบายโดยออบเจ็กต์เริ่มต้นจาก startIdx ช่วงเวลานี้ เมธอดใช้ memcpy() และไม่ได้มีไว้สำหรับสำเนา 0 รายการ การดำเนินการ

ส่งคิวผ่าน HIDL

จากฝั่งของการสร้าง:

  1. สร้างออบเจ็กต์คิวข้อความตามที่อธิบายไว้ข้างต้น
  2. ตรวจสอบว่าออบเจ็กต์ถูกต้องด้วย isValid()
  3. หากคุณรอหลายคิวโดยการส่ง EventFlag สำหรับวิดีโอแบบยาว readBlocking()/writeBlocking() คุณสามารถดึงข้อมูล ตัวชี้สถานะเหตุการณ์ (โดยใช้ getEventFlagWord()) จาก MessageQueue ออบเจ็กต์ที่เริ่มต้นเพื่อสร้าง Flag และ ให้ใช้ Flag นั้นเพื่อสร้างออบเจ็กต์ EventFlag ที่จำเป็น
  4. ใช้เมธอด MessageQueue getDesc() เพื่อรับ ออบเจ็กต์ข้อบ่งชี้
  5. ในไฟล์ .hal ให้กำหนดพารามิเตอร์ประเภท fmq_sync หรือ fmq_unsync โดยที่ T เป็น ประเภทที่กำหนดโดย HIDL ที่เหมาะสม ใช้ค่านี้เพื่อส่งออบเจ็กต์ที่ส่งคืนโดย getDesc()ไปยังขั้นตอนการรับ

ฝั่งผู้รับ:

  1. ใช้ออบเจ็กต์ข้อบ่งชี้เพื่อสร้างออบเจ็กต์ MessageQueue เป็น ให้ใช้รูปแบบและประเภทข้อมูลเดียวกันของคิว ไม่เช่นนั้นเทมเพลตไม่สามารถ คอมไพล์
  2. ถ้าคุณดึงค่าสถานะเหตุการณ์ ให้แยกค่าสถานะจาก MessageQueue ออบเจ็กต์ในกระบวนการรับ
  3. ใช้ออบเจ็กต์ MessageQueue เพื่อโอนข้อมูล