โครงสร้างพื้นฐานของ Remote Process Call (RPC) ของ HIDL ใช้กลไก Binder ซึ่งหมายความว่าการเรียกใช้มีค่าใช้จ่าย ต้องใช้การดำเนินการเคอร์เนล และทริกเกอร์การดำเนินการกำหนดเวลาได้ อย่างไรก็ตาม ในกรณีที่ต้องโอนข้อมูลระหว่างกระบวนการที่มีค่าใช้จ่ายเพิ่มเติมน้อยลงและไม่เกี่ยวข้องกับเคอร์เนล ระบบจะใช้คิวข้อความด่วน (FMQ)
FMQ จะสร้างคิวข้อความที่มีพร็อพเพอร์ตี้ที่ต้องการ คุณสามารถส่งออบเจ็กต์ MQDescriptorSync
หรือ MQDescriptorUnsync
ผ่านคอล HIDL RPC และกระบวนการฝั่งที่รับจะใช้ออบเจ็กต์ดังกล่าวเพื่อเข้าถึงคิวข้อความ
ประเภทคิว
Android รองรับคิว 2 ประเภท (เรียกว่าตัวแปร) ดังนี้
- คิวที่ไม่ได้ซิงค์จะอนุญาตให้มีรายการเกินจำนวนที่อนุญาตได้ และมีตัวอ่านได้หลายตัว โดยตัวอ่านแต่ละตัวต้องอ่านข้อมูลให้ทันเวลา ไม่เช่นนั้นข้อมูลจะหายไป
- คิวที่ซิงค์จะไม่อนุญาตให้มีรายการเกินขีดจำกัด และมีเครื่องอ่านได้เพียงเครื่องเดียว
ทั้ง 2 ประเภทของคิวไม่อนุญาตให้เกิด Underflow (อ่านจากคิวว่างไม่สำเร็จ) และมีผู้เขียนได้เพียงคนเดียว
คิวที่ไม่ได้ซิงค์
คิวที่ไม่มีการซิงค์จะมีผู้เขียนเพียงคนเดียว แต่อาจมีผู้อ่านกี่คนก็ได้ มีการเขียนตำแหน่งเดียวสำหรับคิว แต่เครื่องอ่านแต่ละเครื่องจะติดตามตำแหน่งการอ่านอิสระของตนเอง
การเขียนลงในคิวจะสำเร็จเสมอ (ไม่มีการตรวจสอบการเขียนที่เกิน) ตราบใดที่ข้อมูลมีขนาดไม่เกินความจุของคิวที่กําหนดค่าไว้ (การเขียนที่มีขนาดใหญ่กว่าความจุของคิวจะดำเนินการไม่สำเร็จทันที) เนื่องจากผู้อ่านแต่ละรายอาจมีตําแหน่งการอ่านต่างกัน ระบบจึงจะยกเลิกคิวข้อมูลทุกครั้งที่มีการเขียนใหม่ที่ต้องการพื้นที่ แทนที่จะรอให้ผู้อ่านทุกคนอ่านข้อมูลทุกรายการ
ผู้อ่านมีหน้าที่รับผิดชอบในการดึงข้อมูลก่อนที่จะหลุดออกจากคิว การอ่านที่พยายามอ่านข้อมูลมากกว่าที่มีจะดำเนินการไม่สำเร็จทันที (หากไม่ใช่แบบบล็อก) หรือรอให้ข้อมูลพร้อมใช้งานเพียงพอ (หากเป็นแบบบล็อก) การอ่านที่พยายามอ่านข้อมูลมากกว่าความจุของคิวจะล้มเหลวในทันที
หากเครื่องอ่านตามไม่ทันเครื่องเขียน ดังนั้นปริมาณข้อมูลที่เขียนและเครื่องอ่านยังไม่ได้อ่านจะมากกว่าความจุของคิว การอ่านครั้งถัดไปจะไม่แสดงข้อมูล แต่ระบบจะรีเซ็ตตําแหน่งการอ่านของเครื่องอ่านให้เท่ากับตําแหน่งการเขียนล่าสุด แล้วแสดงผลว่าไม่สําเร็จ หากมีการตรวจสอบข้อมูลที่พร้อมให้อ่านหลังจากเกิดเหตุการณ์ "ข้อมูลล้น" แต่ก่อนการอ่านครั้งถัดไป ระบบจะแสดงข้อมูลที่พร้อมให้อ่านมากกว่าความจุของคิว ซึ่งบ่งบอกว่าเกิดเหตุการณ์ "ข้อมูลล้น" (หากคิวล้นระหว่างการตรวจสอบข้อมูลที่มีอยู่และพยายามอ่านข้อมูลดังกล่าว สิ่งบ่งชี้เพียงอย่างเดียวที่บ่งบอกถึงข้อมูลล้นคือระบบอ่านไม่สำเร็จ)
คิวที่ซิงค์
คิวที่ซิงค์จะมีผู้เขียน 1 คนและผู้อ่าน 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 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 ที่ 2
ระบบจะสร้างอีกด้านหนึ่งของคิวข้อความโดยใช้ออบเจ็กต์ MQDescriptor
ที่ได้มาจากอีกด้านหนึ่ง ระบบจะส่งออบเจ็กต์ MQDescriptor
ผ่านคอล HIDL หรือ AIDL RPC ไปยังกระบวนการที่ถือปลายทางที่ 2 ของคิวข้อความ ไฟล์ 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
ทั้งหมดตามที่อธิบายไว้ในส่วนนี้
คิวการบล็อกและ Flag เหตุการณ์
โดยค่าเริ่มต้น คิวจะไม่รองรับการบล็อกการอ่านและเขียน การบล็อกการเรียกใช้การอ่านและการเขียนมี 2 ประเภท ได้แก่
- รูปแบบย่อซึ่งมีพารามิเตอร์ 3 รายการ (ตัวชี้ข้อมูล จำนวนรายการ และเวลาหมด) รองรับการบล็อกการดำเนินการอ่านและเขียนแต่ละรายการในคิวเดียว เมื่อใช้รูปแบบนี้ คิวจะจัดการ Flag เหตุการณ์และบิตมาสก์ภายใน และออบเจ็กต์คิวข้อความแรกต้องได้รับการเริ่มต้นด้วยพารามิเตอร์ที่ 2 ของ
true
เช่น// For an unsynchronized FMQ that supports blocking mFmqUnsynchronizedBlocking = new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite> (kNumElementsInQueue, true /* enable blocking operations */);
- รูปแบบยาวซึ่งมีพารามิเตอร์ 6 รายการ (รวม Flag เหตุการณ์และบิตมาสก์)
รองรับการใช้ออบเจ็กต์
EventFlag
ที่แชร์ระหว่างคิวหลายรายการ และอนุญาตให้ระบุบิตมาสก์การแจ้งเตือนที่จะใช้ ในกรณีนี้ คุณต้องระบุ Flag เหตุการณ์และบิตมาสก์ในการเรียกใช้การอ่านและเขียนแต่ละครั้ง
สำหรับรูปแบบยาว คุณสามารถระบุ EventFlag
อย่างชัดเจนในreadBlocking()
และ writeBlocking()
คุณสามารถเริ่มต้นคิวรายการใดรายการหนึ่งด้วย Flag เหตุการณ์ภายใน ซึ่งจะต้องดึงมาจากออบเจ็กต์ 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
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 หมายความว่าจะไม่หมดเวลา)
การดำเนินการบล็อกจะใช้คํา Flag เหตุการณ์ โดยค่าเริ่มต้น แต่ละคิวจะสร้างและใช้คําแจ้งของตนเองเพื่อรองรับreadBlocking()
และ writeBlocking()
แบบย่อ คิวหลายรายการสามารถใช้คําเดียวกันได้ เพื่อให้กระบวนการรอการเขียนหรืออ่านคิวใดก็ได้ การเรียกใช้ getEventFlagWord()
จะทำให้คุณได้รับพอยน์เตอร์ไปยังคำ Flag เหตุการณ์ของคิว และสามารถใช้พอยน์เตอร์ดังกล่าว (หรือพอยน์เตอร์ไปยังตำแหน่งหน่วยความจำที่แชร์ที่เหมาะสม) เพื่อสร้างออบเจ็กต์ EventFlag
เพื่อส่งไปยังรูปแบบยาวของ readBlocking()
และ writeBlocking()
สำหรับคิวอื่น พารามิเตอร์ readNotification
และ writeNotification
จะบอกให้ทราบว่าควรใช้บิตใดใน Flag เหตุการณ์เพื่อส่งสัญญาณการอ่านและการเขียนในคิวนั้น 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 เดียวกัน เพื่อปรับปรุงประสิทธิภาพ 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
รายการแรกและที่ 2 ภายในออบเจ็กต์ 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-1bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
จะเขียนnMessages
รายการประเภทT
ไปยังภูมิภาคหน่วยความจำที่อธิบายโดยออบเจ็กต์ โดยเริ่มจากดัชนีstartIdx
วิธีนี้ใช้memcpy()
และไม่ได้มีไว้สำหรับการดำเนินการแบบการคัดลอกข้อมูลเพียงครั้งเดียว หากออบเจ็กต์MemTransaction
แสดงหน่วยความจําสําหรับอ่านและเขียนรายการประเภทT
จำนวน N รายการ ช่วงของidx
ที่ถูกต้องจะอยู่ในช่วง 0 ถึง N-1bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
เป็นเมธอดตัวช่วยในการอ่านรายการnMessages
ประเภทT
จากภูมิภาคหน่วยความจำที่อธิบายโดยออบเจ็กต์โดยเริ่มจากstartIdx
วิธีนี้ใช้memcpy()
และไม่ได้มีไว้สำหรับการดำเนินการแบบไม่ทำสำเนา
ส่งคิวผ่าน HIDL
จากฝั่งของการสร้าง:
- สร้างออบเจ็กต์คิวข้อความตามที่อธิบายไว้ข้างต้น
- ยืนยันว่าวัตถุถูกต้องด้วย
isValid()
- หากกำลังรอคิวหลายคิวโดยส่ง
EventFlag
ไปยังรูปแบบแบบยาวของreadBlocking()
หรือwriteBlocking()
คุณสามารถดึงข้อมูลเคอร์เซอร์ Flag เหตุการณ์ (โดยใช้getEventFlagWord()
) จากออบเจ็กต์MessageQueue
ที่เริ่มต้นเพื่อสร้าง Flag และนำ Flag นั้นไปสร้างออบเจ็กต์EventFlag
ที่จำเป็น - ใช้เมธอด
MessageQueue
getDesc()
เพื่อรับออบเจ็กต์ข้อบ่งชี้ - ในไฟล์ HAL ให้ตั้งค่าพารามิเตอร์ของเมธอดเป็นประเภท
fmq_sync
หรือfmq_unsync
โดยที่T
เป็นประเภทที่ HIDL กำหนดไว้ซึ่งเหมาะสม ใช้เพื่อส่งออบเจ็กต์ที่getDesc()
แสดงผลไปยังกระบวนการรับ
ฝั่งที่รับ
- ใช้ออบเจ็กต์ตัวบ่งชี้เพื่อสร้างออบเจ็กต์
MessageQueue
ใช้เวอร์ชันและประเภทข้อมูลเดียวกัน ไม่เช่นนั้นระบบจะคอมไพล์เทมเพลตไม่สำเร็จ - หากคุณดึงข้อมูล Flag เหตุการณ์ ให้ดึง Flag นั้นจากออบเจ็กต์
MessageQueue
ที่เกี่ยวข้องในกระบวนการรับ - ใช้ออบเจ็กต์
MessageQueue
เพื่อโอนข้อมูล