• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef HIDL_MQ_H
18 #define HIDL_MQ_H
19 
20 #include <atomic>
21 #include <cutils/ashmem.h>
22 #include <fmq/EventFlag.h>
23 #include <hidl/MQDescriptor.h>
24 #include <new>
25 #include <sys/mman.h>
26 #include <utils/Log.h>
27 #include <utils/SystemClock.h>
28 
29 namespace android {
30 namespace hardware {
31 
32 namespace details {
33 void check(bool exp);
34 void logError(const std::string &message);
35 }  // namespace details
36 
37 template <typename T, MQFlavor flavor>
38 struct MessageQueue {
39     typedef MQDescriptor<T, flavor> Descriptor;
40 
41     /**
42      * @param Desc MQDescriptor describing the FMQ.
43      * @param resetPointers bool indicating whether the read/write pointers
44      * should be reset or not.
45      */
46     MessageQueue(const Descriptor& Desc, bool resetPointers = true);
47 
48     ~MessageQueue();
49 
50     /**
51      * This constructor uses Ashmem shared memory to create an FMQ
52      * that can contain a maximum of 'numElementsInQueue' elements of type T.
53      *
54      * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
55      * @param configureEventFlagWord Boolean that specifies if memory should
56      * also be allocated and mapped for an EventFlag word.
57      */
58     MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
59 
60     /**
61      * @return Number of items of type T that can be written into the FMQ
62      * without a read.
63      */
64     size_t availableToWrite() const;
65 
66     /**
67      * @return Number of items of type T that are waiting to be read from the
68      * FMQ.
69      */
70     size_t availableToRead() const;
71 
72     /**
73      * Returns the size of type T in bytes.
74      *
75      * @param Size of T.
76      */
77     size_t getQuantumSize() const;
78 
79     /**
80      * Returns the size of the FMQ in terms of the size of type T.
81      *
82      * @return Number of items of type T that will fit in the FMQ.
83      */
84     size_t getQuantumCount() const;
85 
86     /**
87      * @return Whether the FMQ is configured correctly.
88      */
89     bool isValid() const;
90 
91     /**
92      * Non-blocking write to FMQ.
93      *
94      * @param data Pointer to the object of type T to be written into the FMQ.
95      *
96      * @return Whether the write was successful.
97      */
98     bool write(const T* data);
99 
100     /**
101      * Non-blocking read from FMQ.
102      *
103      * @param data Pointer to the memory where the object read from the FMQ is
104      * copied to.
105      *
106      * @return Whether the read was successful.
107      */
108     bool read(T* data);
109 
110     /**
111      * Write some data into the FMQ without blocking.
112      *
113      * @param data Pointer to the array of items of type T.
114      * @param count Number of items in array.
115      *
116      * @return Whether the write was successful.
117      */
118     bool write(const T* data, size_t count);
119 
120     /**
121      * Perform a blocking write of 'count' items into the FMQ using EventFlags.
122      * Does not support partial writes.
123      *
124      * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
125      * associated with the FMQ and it is used in that case.
126      *
127      * The application code must ensure that 'evFlag' used by the
128      * reader(s)/writer is based upon the same EventFlag word.
129      *
130      * The method will return false without blocking if any of the following
131      * conditions are true:
132      * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
133      * - If the 'readNotification' bit mask is zero.
134      * - If 'count' is greater than the FMQ size.
135      *
136      * If the there is insufficient space available to write into it, the
137      * EventFlag bit mask 'readNotification' is is waited upon.
138      *
139      * This method should only be used with a MessageQueue of the flavor
140      * 'kSynchronizedReadWrite'.
141      *
142      * Upon a successful write, wake is called on 'writeNotification' (if
143      * non-zero).
144      *
145      * @param data Pointer to the array of items of type T.
146      * @param count Number of items in array.
147      * @param readNotification The EventFlag bit mask to wait on if there is not
148      * enough space in FMQ to write 'count' items.
149      * @param writeNotification The EventFlag bit mask to call wake on
150      * a successful write. No wake is called if 'writeNotification' is zero.
151      * @param timeOutNanos Number of nanoseconds after which the blocking
152      * write attempt is aborted.
153      * @param evFlag The EventFlag object to be used for blocking. If nullptr,
154      * it is checked whether the FMQ owns an EventFlag object and that is used
155      * for blocking instead.
156      *
157      * @return Whether the write was successful.
158      */
159     bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
160                        uint32_t writeNotification, int64_t timeOutNanos = 0,
161                        android::hardware::EventFlag* evFlag = nullptr);
162 
163     bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
164 
165     /**
166      * Read some data from the FMQ without blocking.
167      *
168      * @param data Pointer to the array to which read data is to be written.
169      * @param count Number of items to be read.
170      *
171      * @return Whether the read was successful.
172      */
173     bool read(T* data, size_t count);
174 
175     /**
176      * Perform a blocking read operation of 'count' items from the FMQ. Does not
177      * perform a partial read.
178      *
179      * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
180      * associated with the FMQ and it is used in that case.
181      *
182      * The application code must ensure that 'evFlag' used by the
183      * reader(s)/writer is based upon the same EventFlag word.
184      *
185      * The method will return false without blocking if any of the following
186      * conditions are true:
187      * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
188      * -If the 'writeNotification' bit mask is zero.
189      * -If 'count' is greater than the FMQ size.
190      *
191      * This method should only be used with a MessageQueue of the flavor
192      * 'kSynchronizedReadWrite'.
193 
194      * If FMQ does not contain 'count' items, the eventFlag bit mask
195      * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
196      * wake is called on 'readNotification' (if non-zero).
197      *
198      * @param data Pointer to the array to which read data is to be written.
199      * @param count Number of items to be read.
200      * @param readNotification The EventFlag bit mask to call wake on after
201      * a successful read. No wake is called if 'readNotification' is zero.
202      * @param writeNotification The EventFlag bit mask to call a wait on
203      * if there is insufficient data in the FMQ to be read.
204      * @param timeOutNanos Number of nanoseconds after which the blocking
205      * read attempt is aborted.
206      * @param evFlag The EventFlag object to be used for blocking.
207      *
208      * @return Whether the read was successful.
209      */
210     bool readBlocking(T* data, size_t count, uint32_t readNotification,
211                       uint32_t writeNotification, int64_t timeOutNanos = 0,
212                       android::hardware::EventFlag* evFlag = nullptr);
213 
214     bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
215 
216     /**
217      * Get a pointer to the MQDescriptor object that describes this FMQ.
218      *
219      * @return Pointer to the MQDescriptor associated with the FMQ.
220      */
getDescMessageQueue221     const Descriptor* getDesc() const { return mDesc.get(); }
222 
223     /**
224      * Get a pointer to the EventFlag word if there is one associated with this FMQ.
225      *
226      * @return Pointer to an EventFlag word, will return nullptr if not
227      * configured. This method does not transfer ownership. The EventFlag
228      * word will be unmapped by the MessageQueue destructor.
229      */
getEventFlagWordMessageQueue230     std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
231 
232     /**
233      * Describes a memory region in the FMQ.
234      */
235     struct MemRegion {
MemRegionMessageQueue::MemRegion236         MemRegion() : MemRegion(nullptr, 0) {}
237 
MemRegionMessageQueue::MemRegion238         MemRegion(T* base, size_t size) : address(base), length(size) {}
239 
240         MemRegion& operator=(const MemRegion &other) {
241             address = other.address;
242             length = other.length;
243             return *this;
244         }
245 
246         /**
247          * Gets a pointer to the base address of the MemRegion.
248          */
getAddressMessageQueue::MemRegion249         inline T* getAddress() const { return address; }
250 
251         /**
252          * Gets the length of the MemRegion. This would equal to the number
253          * of items of type T that can be read from/written into the MemRegion.
254          */
getLengthMessageQueue::MemRegion255         inline size_t getLength() const { return length; }
256 
257         /**
258          * Gets the length of the MemRegion in bytes.
259          */
getLengthInBytesMessageQueue::MemRegion260         inline size_t getLengthInBytes() const { return length * sizeof(T); }
261 
262     private:
263         /* Base address */
264         T* address;
265 
266         /*
267          * Number of items of type T that can be written to/read from the base
268          * address.
269          */
270         size_t length;
271     };
272 
273     /**
274      * Describes the memory regions to be used for a read or write.
275      * The struct contains two MemRegion objects since the FMQ is a ring
276      * buffer and a read or write operation can wrap around. A single message
277      * of type T will never be broken between the two MemRegions.
278      */
279     struct MemTransaction {
MemTransactionMessageQueue::MemTransaction280         MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
281 
MemTransactionMessageQueue::MemTransaction282         MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond) :
283             first(regionFirst), second(regionSecond) {}
284 
285         MemTransaction& operator=(const MemTransaction &other) {
286             first = other.first;
287             second = other.second;
288             return *this;
289         }
290 
291         /**
292          * Helper method to calculate the address for a particular index for
293          * the MemTransaction object.
294          *
295          * @param idx Index of the slot to be read/written. If the
296          * MemTransaction object is representing the memory region to read/write
297          * N items of type T, the valid range of idx is between 0 and N-1.
298          *
299          * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
300          */
301         T* getSlot(size_t idx);
302 
303         /**
304          * Helper method to write 'nMessages' items of type T into the memory
305          * regions described by the object starting from 'startIdx'. This method
306          * uses memcpy() and is not to meant to be used for a zero copy operation.
307          * Partial writes are not supported.
308          *
309          * @param data Pointer to the source buffer.
310          * @param nMessages Number of items of type T.
311          * @param startIdx The slot number to begin the write from. If the
312          * MemTransaction object is representing the memory region to read/write
313          * N items of type T, the valid range of startIdx is between 0 and N-1;
314          *
315          * @return Whether the write operation of size 'nMessages' succeeded.
316          */
317         bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
318 
319         /*
320          * Helper method to read 'nMessages' items of type T from the memory
321          * regions described by the object starting from 'startIdx'. This method uses
322          * memcpy() and is not meant to be used for a zero copy operation. Partial reads
323          * are not supported.
324          *
325          * @param data Pointer to the destination buffer.
326          * @param nMessages Number of items of type T.
327          * @param startIdx The slot number to begin the read from. If the
328          * MemTransaction object is representing the memory region to read/write
329          * N items of type T, the valid range of startIdx is between 0 and N-1.
330          *
331          * @return Whether the read operation of size 'nMessages' succeeded.
332          */
333         bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
334 
335         /**
336          * Returns a const reference to the first MemRegion in the
337          * MemTransaction object.
338          */
getFirstRegionMessageQueue::MemTransaction339         inline const MemRegion& getFirstRegion() const { return first; }
340 
341         /**
342          * Returns a const reference to the second MemRegion in the
343          * MemTransaction object.
344          */
getSecondRegionMessageQueue::MemTransaction345         inline const MemRegion& getSecondRegion() const { return second; }
346 
347     private:
348         /*
349          * Given a start index and the number of messages to be
350          * read/written, this helper method calculates the
351          * number of messages that should should be written to both the first
352          * and second MemRegions and the base addresses to be used for
353          * the read/write operation.
354          *
355          * Returns false if the 'startIdx' and 'nMessages' is
356          * invalid for the MemTransaction object.
357          */
358         bool inline getMemRegionInfo(size_t idx,
359                                      size_t nMessages,
360                                      size_t& firstCount,
361                                      size_t& secondCount,
362                                      T** firstBaseAddress,
363                                      T** secondBaseAddress);
364         MemRegion first;
365         MemRegion second;
366     };
367 
368     /**
369      * Get a MemTransaction object to write 'nMessages' items of type T.
370      * Once the write is performed using the information from MemTransaction,
371      * the write operation is to be committed using a call to commitWrite().
372      *
373      * @param nMessages Number of messages of type T.
374      * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
375      * items of type T. If a write of size 'nMessages' is not possible, the base
376      * addresses in the MemTransaction object would be set to nullptr.
377      *
378      * @return Whether it is possible to write 'nMessages' items of type T
379      * into the FMQ.
380      */
381     bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
382 
383     /**
384      * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
385      *
386      * @param nMessages number of messages of type T to be written.
387      *
388      * @return Whether the write operation of size 'nMessages' succeeded.
389      */
390     bool commitWrite(size_t nMessages);
391 
392     /**
393      * Get a MemTransaction object to read 'nMessages' items of type T.
394      * Once the read is performed using the information from MemTransaction,
395      * the read operation is to be committed using a call to commitRead().
396      *
397      * @param nMessages Number of messages of type T.
398      * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
399      * items of type T. If a read of size 'nMessages' is not possible, the base
400      * pointers in the MemTransaction object returned will be set to nullptr.
401      *
402      * @return bool Whether it is possible to read 'nMessages' items of type T
403      * from the FMQ.
404      */
405     bool beginRead(size_t nMessages, MemTransaction* memTx) const;
406 
407     /**
408      * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
409      * For the unsynchronized flavor of FMQ, this method will return a failure
410      * if a write overflow happened after beginRead() was invoked.
411      *
412      * @param nMessages number of messages of type T to be read.
413      *
414      * @return bool Whether the read operation of size 'nMessages' succeeded.
415      */
416     bool commitRead(size_t nMessages);
417 
418 private:
419 
420     size_t availableToWriteBytes() const;
421     size_t availableToReadBytes() const;
422 
423     MessageQueue(const MessageQueue& other) = delete;
424     MessageQueue& operator=(const MessageQueue& other) = delete;
425     MessageQueue();
426 
427     void* mapGrantorDescr(uint32_t grantorIdx);
428     void unmapGrantorDescr(void* address, uint32_t grantorIdx);
429     void initMemory(bool resetPointers);
430 
431     enum DefaultEventNotification : uint32_t {
432         /*
433          * These are only used internally by the readBlocking()/writeBlocking()
434          * methods and hence once other bit combinations are not required.
435          */
436         FMQ_NOT_FULL = 0x01,
437         FMQ_NOT_EMPTY = 0x02
438     };
439 
440     std::unique_ptr<Descriptor> mDesc;
441     uint8_t* mRing = nullptr;
442     /*
443      * TODO(b/31550092): Change to 32 bit read and write pointer counters.
444      */
445     std::atomic<uint64_t>* mReadPtr = nullptr;
446     std::atomic<uint64_t>* mWritePtr = nullptr;
447 
448     std::atomic<uint32_t>* mEvFlagWord = nullptr;
449 
450     /*
451      * This EventFlag object will be owned by the FMQ and will have the same
452      * lifetime.
453      */
454     android::hardware::EventFlag* mEventFlag = nullptr;
455 };
456 
457 template <typename T, MQFlavor flavor>
getSlot(size_t idx)458 T* MessageQueue<T, flavor>::MemTransaction::getSlot(size_t idx) {
459     size_t firstRegionLength = first.getLength();
460     size_t secondRegionLength = second.getLength();
461 
462     if (idx > firstRegionLength + secondRegionLength) {
463         return nullptr;
464     }
465 
466     if (idx < firstRegionLength) {
467         return first.getAddress() + idx;
468     }
469 
470     return second.getAddress() + idx - firstRegionLength;
471 }
472 
473 template <typename T, MQFlavor flavor>
getMemRegionInfo(size_t startIdx,size_t nMessages,size_t & firstCount,size_t & secondCount,T ** firstBaseAddress,T ** secondBaseAddress)474 bool MessageQueue<T, flavor>::MemTransaction::getMemRegionInfo(size_t startIdx,
475                                                                size_t nMessages,
476                                                                size_t& firstCount,
477                                                                size_t& secondCount,
478                                                                T** firstBaseAddress,
479                                                                T** secondBaseAddress) {
480     size_t firstRegionLength = first.getLength();
481     size_t secondRegionLength = second.getLength();
482 
483     if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
484         /*
485          * Return false if 'nMessages' starting at 'startIdx' cannot be
486          * accomodated by the MemTransaction object.
487          */
488         return false;
489     }
490 
491     /* Number of messages to be read/written to the first MemRegion. */
492     firstCount = startIdx < firstRegionLength ?
493             std::min(nMessages, firstRegionLength - startIdx) : 0;
494 
495     /* Number of messages to be read/written to the second MemRegion. */
496     secondCount = nMessages - firstCount;
497 
498     if (firstCount != 0) {
499         *firstBaseAddress = first.getAddress() + startIdx;
500     }
501 
502     if (secondCount != 0) {
503         size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
504         *secondBaseAddress = second.getAddress() + secondStartIdx;
505     }
506 
507     return true;
508 }
509 
510 template <typename T, MQFlavor flavor>
copyFrom(T * data,size_t startIdx,size_t nMessages)511 bool MessageQueue<T, flavor>::MemTransaction::copyFrom(T* data, size_t startIdx, size_t nMessages) {
512     if (data == nullptr) {
513         return false;
514     }
515 
516     size_t firstReadCount = 0, secondReadCount = 0;
517     T* firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
518 
519     if (getMemRegionInfo(startIdx,
520                          nMessages,
521                          firstReadCount,
522                          secondReadCount,
523                          &firstBaseAddress,
524                          &secondBaseAddress) == false) {
525         /*
526          * Returns false if 'startIdx' and 'nMessages' are invalid for this
527          * MemTransaction object.
528          */
529         return false;
530     }
531 
532     if (firstReadCount != 0) {
533         memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
534     }
535 
536     if (secondReadCount != 0) {
537         memcpy(data + firstReadCount,
538                secondBaseAddress,
539                secondReadCount * sizeof(T));
540     }
541 
542     return true;
543 }
544 
545 template <typename T, MQFlavor flavor>
copyTo(const T * data,size_t startIdx,size_t nMessages)546 bool MessageQueue<T, flavor>::MemTransaction::copyTo(const T* data,
547                                                      size_t startIdx,
548                                                      size_t nMessages) {
549     if (data == nullptr) {
550         return false;
551     }
552 
553     size_t firstWriteCount = 0, secondWriteCount = 0;
554     T * firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
555 
556     if (getMemRegionInfo(startIdx,
557                          nMessages,
558                          firstWriteCount,
559                          secondWriteCount,
560                          &firstBaseAddress,
561                          &secondBaseAddress) == false) {
562         /*
563          * Returns false if 'startIdx' and 'nMessages' are invalid for this
564          * MemTransaction object.
565          */
566         return false;
567     }
568 
569     if (firstWriteCount != 0) {
570         memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
571     }
572 
573     if (secondWriteCount != 0) {
574         memcpy(secondBaseAddress,
575                data + firstWriteCount,
576                secondWriteCount * sizeof(T));
577     }
578 
579     return true;
580 }
581 
582 template <typename T, MQFlavor flavor>
initMemory(bool resetPointers)583 void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
584     /*
585      * Verify that the the Descriptor contains the minimum number of grantors
586      * the native_handle is valid and T matches quantum size.
587      */
588     if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
589         (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
590         (mDesc->getQuantum() != sizeof(T))) {
591         return;
592     }
593 
594     if (flavor == kSynchronizedReadWrite) {
595         mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
596                 mapGrantorDescr(Descriptor::READPTRPOS));
597     } else {
598         /*
599          * The unsynchronized write flavor of the FMQ may have multiple readers
600          * and each reader would have their own read pointer counter.
601          */
602         mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
603     }
604 
605     details::check(mReadPtr != nullptr);
606 
607     mWritePtr =
608             reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
609     details::check(mWritePtr != nullptr);
610 
611     if (resetPointers) {
612         mReadPtr->store(0, std::memory_order_release);
613         mWritePtr->store(0, std::memory_order_release);
614     } else if (flavor != kSynchronizedReadWrite) {
615         // Always reset the read pointer.
616         mReadPtr->store(0, std::memory_order_release);
617     }
618 
619     mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
620     details::check(mRing != nullptr);
621 
622     mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
623     if (mEvFlagWord != nullptr) {
624         android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
625     }
626 }
627 
628 template <typename T, MQFlavor flavor>
MessageQueue(const Descriptor & Desc,bool resetPointers)629 MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
630     mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
631     if (mDesc == nullptr) {
632         return;
633     }
634 
635     initMemory(resetPointers);
636 }
637 
638 template <typename T, MQFlavor flavor>
MessageQueue(size_t numElementsInQueue,bool configureEventFlagWord)639 MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
640 
641     // Check if the buffer size would not overflow size_t
642     if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
643         return;
644     }
645     /*
646      * The FMQ needs to allocate memory for the ringbuffer as well as for the
647      * read and write pointer counters. If an EventFlag word is to be configured,
648      * we also need to allocate memory for the same/
649      */
650     size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
651     size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
652 
653     if (configureEventFlagWord) {
654         kMetaDataSize+= sizeof(std::atomic<uint32_t>);
655     }
656 
657     /*
658      * Ashmem memory region size needs to be specified in page-aligned bytes.
659      * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
660      * in the grantorDescriptor will be word aligned.
661      */
662     size_t kAshmemSizePageAligned =
663             (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
664             ~(PAGE_SIZE - 1);
665 
666     /*
667      * Create an ashmem region to map the memory for the ringbuffer,
668      * read counter and write counter.
669      */
670     int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
671     ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
672 
673     /*
674      * The native handle will contain the fds to be mapped.
675      */
676     native_handle_t* mqHandle =
677             native_handle_create(1 /* numFds */, 0 /* numInts */);
678     if (mqHandle == nullptr) {
679         return;
680     }
681 
682     mqHandle->data[0] = ashmemFd;
683     mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
684                                                                       mqHandle,
685                                                                       sizeof(T),
686                                                                       configureEventFlagWord));
687     if (mDesc == nullptr) {
688         return;
689     }
690     initMemory(true);
691 }
692 
693 template <typename T, MQFlavor flavor>
~MessageQueue()694 MessageQueue<T, flavor>::~MessageQueue() {
695     if (flavor == kUnsynchronizedWrite) {
696         delete mReadPtr;
697     } else {
698         unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
699     }
700     if (mWritePtr != nullptr) {
701         unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
702     }
703     if (mRing != nullptr) {
704         unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
705     }
706     if (mEvFlagWord != nullptr) {
707         unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
708         android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
709     }
710 }
711 
712 template <typename T, MQFlavor flavor>
write(const T * data)713 bool MessageQueue<T, flavor>::write(const T* data) {
714     return write(data, 1);
715 }
716 
717 template <typename T, MQFlavor flavor>
read(T * data)718 bool MessageQueue<T, flavor>::read(T* data) {
719     return read(data, 1);
720 }
721 
722 template <typename T, MQFlavor flavor>
write(const T * data,size_t nMessages)723 bool MessageQueue<T, flavor>::write(const T* data, size_t nMessages) {
724     MemTransaction tx;
725     return beginWrite(nMessages, &tx) &&
726             tx.copyTo(data, 0 /* startIdx */, nMessages) &&
727             commitWrite(nMessages);
728 }
729 
730 template <typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)731 bool MessageQueue<T, flavor>::writeBlocking(const T* data,
732                                             size_t count,
733                                             uint32_t readNotification,
734                                             uint32_t writeNotification,
735                                             int64_t timeOutNanos,
736                                             android::hardware::EventFlag* evFlag) {
737     static_assert(flavor == kSynchronizedReadWrite,
738                   "writeBlocking can only be used with the "
739                   "kSynchronizedReadWrite flavor.");
740     /*
741      * If evFlag is null and the FMQ does not have its own EventFlag object
742      * return false;
743      * If the flavor is kSynchronizedReadWrite and the readNotification
744      * bit mask is zero return false;
745      * If the count is greater than queue size, return false
746      * to prevent blocking until timeOut.
747      */
748     if (evFlag == nullptr) {
749         evFlag = mEventFlag;
750         if (evFlag == nullptr) {
751             details::logError(
752                 "writeBlocking failed: called on MessageQueue with no Eventflag"
753                 "configured or provided");
754             return false;
755         }
756     }
757 
758     if (readNotification == 0 || (count > getQuantumCount())) {
759         return false;
760     }
761 
762     /*
763      * There is no need to wait for a readNotification if there is sufficient
764      * space to write is already present in the FMQ. The latter would be the case when
765      * read operations read more number of messages than write operations write.
766      * In other words, a single large read may clear the FMQ after multiple small
767      * writes. This would fail to clear a pending readNotification bit since
768      * EventFlag bits can only be cleared by a wait() call, however the bit would
769      * be correctly cleared by the next writeBlocking() call.
770      */
771 
772     bool result = write(data, count);
773     if (result) {
774         if (writeNotification) {
775             evFlag->wake(writeNotification);
776         }
777         return result;
778     }
779 
780     bool shouldTimeOut = timeOutNanos != 0;
781     int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
782 
783     while (true) {
784         /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
785         if (shouldTimeOut) {
786             /*
787              * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
788              * to Nanoseconds)
789              */
790             int64_t currentTimeNs = android::elapsedRealtimeNano();
791             /*
792              * Decrement 'timeOutNanos' to account for the time taken to complete the last
793              * iteration of the while loop.
794              */
795             timeOutNanos -= currentTimeNs - prevTimeNanos;
796             prevTimeNanos = currentTimeNs;
797 
798             if (timeOutNanos <= 0) {
799                 /*
800                  * Attempt write in case a context switch happened outside of
801                  * evFlag->wait().
802                  */
803                 result = write(data, count);
804                 break;
805             }
806         }
807 
808         /*
809          * wait() will return immediately if there was a pending read
810          * notification.
811          */
812         uint32_t efState = 0;
813         status_t status = evFlag->wait(readNotification,
814                                        &efState,
815                                        timeOutNanos,
816                                        true /* retry on spurious wake */);
817 
818         if (status != android::TIMED_OUT && status != android::NO_ERROR) {
819             details::logError("Unexpected error code from EventFlag Wait status " + std::to_string(status));
820             break;
821         }
822 
823         if (status == android::TIMED_OUT) {
824             break;
825         }
826 
827         /*
828          * If there is still insufficient space to write to the FMQ,
829          * keep waiting for another readNotification.
830          */
831         if ((efState & readNotification) && write(data, count)) {
832             result = true;
833             break;
834         }
835     }
836 
837     if (result && writeNotification != 0) {
838         evFlag->wake(writeNotification);
839     }
840 
841     return result;
842 }
843 
844 template <typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,int64_t timeOutNanos)845 bool MessageQueue<T, flavor>::writeBlocking(const T* data,
846                    size_t count,
847                    int64_t timeOutNanos) {
848     return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
849 }
850 
851 template <typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)852 bool MessageQueue<T, flavor>::readBlocking(T* data,
853                                            size_t count,
854                                            uint32_t readNotification,
855                                            uint32_t writeNotification,
856                                            int64_t timeOutNanos,
857                                            android::hardware::EventFlag* evFlag) {
858     static_assert(flavor == kSynchronizedReadWrite,
859                   "readBlocking can only be used with the "
860                   "kSynchronizedReadWrite flavor.");
861 
862     /*
863      * If evFlag is null and the FMQ does not own its own EventFlag object
864      * return false;
865      * If the writeNotification bit mask is zero return false;
866      * If the count is greater than queue size, return false to prevent
867      * blocking until timeOut.
868      */
869     if (evFlag == nullptr) {
870         evFlag = mEventFlag;
871         if (evFlag == nullptr) {
872             details::logError(
873                 "readBlocking failed: called on MessageQueue with no Eventflag"
874                 "configured or provided");
875             return false;
876         }
877     }
878 
879     if (writeNotification == 0 || count > getQuantumCount()) {
880         return false;
881     }
882 
883     /*
884      * There is no need to wait for a write notification if sufficient
885      * data to read is already present in the FMQ. This would be the
886      * case when read operations read lesser number of messages than
887      * a write operation and multiple reads would be required to clear the queue
888      * after a single write operation. This check would fail to clear a pending
889      * writeNotification bit since EventFlag bits can only be cleared
890      * by a wait() call, however the bit would be correctly cleared by the next
891      * readBlocking() call.
892      */
893 
894     bool result = read(data, count);
895     if (result) {
896         if (readNotification) {
897             evFlag->wake(readNotification);
898         }
899         return result;
900     }
901 
902     bool shouldTimeOut = timeOutNanos != 0;
903     int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
904 
905     while (true) {
906         /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
907         if (shouldTimeOut) {
908             /*
909              * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
910              * to Nanoseconds)
911              */
912             int64_t currentTimeNs = android::elapsedRealtimeNano();
913             /*
914              * Decrement 'timeOutNanos' to account for the time taken to complete the last
915              * iteration of the while loop.
916              */
917             timeOutNanos -= currentTimeNs - prevTimeNanos;
918             prevTimeNanos = currentTimeNs;
919 
920             if (timeOutNanos <= 0) {
921                 /*
922                  * Attempt read in case a context switch happened outside of
923                  * evFlag->wait().
924                  */
925                 result = read(data, count);
926                 break;
927             }
928         }
929 
930         /*
931          * wait() will return immediately if there was a pending write
932          * notification.
933          */
934         uint32_t efState = 0;
935         status_t status = evFlag->wait(writeNotification,
936                                        &efState,
937                                        timeOutNanos,
938                                        true /* retry on spurious wake */);
939 
940         if (status != android::TIMED_OUT && status != android::NO_ERROR) {
941             details::logError("Unexpected error code from EventFlag Wait status " + std::to_string(status));
942             break;
943         }
944 
945         if (status == android::TIMED_OUT) {
946             break;
947         }
948 
949         /*
950          * If the data in FMQ is still insufficient, go back to waiting
951          * for another write notification.
952          */
953         if ((efState & writeNotification) && read(data, count)) {
954             result = true;
955             break;
956         }
957     }
958 
959     if (result && readNotification != 0) {
960         evFlag->wake(readNotification);
961     }
962     return result;
963 }
964 
965 template <typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,int64_t timeOutNanos)966 bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
967     return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
968 }
969 
970 template <typename T, MQFlavor flavor>
availableToWriteBytes()971 size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
972     return mDesc->getSize() - availableToReadBytes();
973 }
974 
975 template <typename T, MQFlavor flavor>
availableToWrite()976 size_t MessageQueue<T, flavor>::availableToWrite() const {
977     return availableToWriteBytes() / sizeof(T);
978 }
979 
980 template <typename T, MQFlavor flavor>
availableToRead()981 size_t MessageQueue<T, flavor>::availableToRead() const {
982     return availableToReadBytes() / sizeof(T);
983 }
984 
985 template <typename T, MQFlavor flavor>
beginWrite(size_t nMessages,MemTransaction * result)986 bool MessageQueue<T, flavor>::beginWrite(size_t nMessages, MemTransaction* result) const {
987     /*
988      * If nMessages is greater than size of FMQ or in case of the synchronized
989      * FMQ flavor, if there is not enough space to write nMessages, then return
990      * result with null addresses.
991      */
992     if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
993         nMessages > getQuantumCount()) {
994         *result = MemTransaction();
995         return false;
996     }
997 
998     auto writePtr = mWritePtr->load(std::memory_order_relaxed);
999     size_t writeOffset = writePtr % mDesc->getSize();
1000 
1001     /*
1002      * From writeOffset, the number of messages that can be written
1003      * contiguously without wrapping around the ring buffer are calculated.
1004      */
1005     size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
1006 
1007     if (contiguousMessages < nMessages) {
1008         /*
1009          * Wrap around is required. Both result.first and result.second are
1010          * populated.
1011          */
1012         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset),
1013                                            contiguousMessages),
1014                                  MemRegion(reinterpret_cast<T*>(mRing),
1015                                            nMessages - contiguousMessages));
1016     } else {
1017         /*
1018          * A wrap around is not required to write nMessages. Only result.first
1019          * is populated.
1020          */
1021         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1022                                  MemRegion());
1023     }
1024 
1025     return true;
1026 }
1027 
1028 template <typename T, MQFlavor flavor>
1029 /*
1030  * Disable integer sanitization since integer overflow here is allowed
1031  * and legal.
1032  */
1033 __attribute__((no_sanitize("integer")))
commitWrite(size_t nMessages)1034 bool MessageQueue<T, flavor>::commitWrite(size_t nMessages) {
1035     size_t nBytesWritten = nMessages * sizeof(T);
1036     auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1037     writePtr += nBytesWritten;
1038     mWritePtr->store(writePtr, std::memory_order_release);
1039     /*
1040      * This method cannot fail now since we are only incrementing the writePtr
1041      * counter.
1042      */
1043     return true;
1044 }
1045 
1046 template <typename T, MQFlavor flavor>
availableToReadBytes()1047 size_t MessageQueue<T, flavor>::availableToReadBytes() const {
1048     /*
1049      * This method is invoked by implementations of both read() and write() and
1050      * hence requries a memory_order_acquired load for both mReadPtr and
1051      * mWritePtr.
1052      */
1053     return mWritePtr->load(std::memory_order_acquire) -
1054             mReadPtr->load(std::memory_order_acquire);
1055 }
1056 
1057 template <typename T, MQFlavor flavor>
read(T * data,size_t nMessages)1058 bool MessageQueue<T, flavor>::read(T* data, size_t nMessages) {
1059     MemTransaction tx;
1060     return beginRead(nMessages, &tx) &&
1061             tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1062             commitRead(nMessages);
1063 }
1064 
1065 template <typename T, MQFlavor flavor>
1066 /*
1067  * Disable integer sanitization since integer overflow here is allowed
1068  * and legal.
1069  */
1070 __attribute__((no_sanitize("integer")))
beginRead(size_t nMessages,MemTransaction * result)1071 bool MessageQueue<T, flavor>::beginRead(size_t nMessages, MemTransaction* result) const {
1072     *result = MemTransaction();
1073     /*
1074      * If it is detected that the data in the queue was overwritten
1075      * due to the reader process being too slow, the read pointer counter
1076      * is set to the same as the write pointer counter to indicate error
1077      * and the read returns false;
1078      * Need acquire/release memory ordering for mWritePtr.
1079      */
1080     auto writePtr = mWritePtr->load(std::memory_order_acquire);
1081     /*
1082      * A relaxed load is sufficient for mReadPtr since there will be no
1083      * stores to mReadPtr from a different thread.
1084      */
1085     auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1086 
1087     if (writePtr - readPtr > mDesc->getSize()) {
1088         mReadPtr->store(writePtr, std::memory_order_release);
1089         return false;
1090     }
1091 
1092     size_t nBytesDesired = nMessages * sizeof(T);
1093     /*
1094      * Return if insufficient data to read in FMQ.
1095      */
1096     if (writePtr - readPtr < nBytesDesired) {
1097         return false;
1098     }
1099 
1100     size_t readOffset = readPtr % mDesc->getSize();
1101     /*
1102      * From readOffset, the number of messages that can be read contiguously
1103      * without wrapping around the ring buffer are calculated.
1104      */
1105     size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1106 
1107     if (contiguousMessages < nMessages) {
1108         /*
1109          * A wrap around is required. Both result.first and result.second
1110          * are populated.
1111          */
1112         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset),
1113                                            contiguousMessages),
1114                                  MemRegion(reinterpret_cast<T*>(mRing),
1115                                            nMessages - contiguousMessages));
1116     } else {
1117         /*
1118          * A wrap around is not required. Only result.first need to be
1119          * populated.
1120          */
1121         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1122                                  MemRegion());
1123     }
1124 
1125     return true;
1126 }
1127 
1128 template <typename T, MQFlavor flavor>
1129 /*
1130  * Disable integer sanitization since integer overflow here is allowed
1131  * and legal.
1132  */
1133 __attribute__((no_sanitize("integer")))
commitRead(size_t nMessages)1134 bool MessageQueue<T, flavor>::commitRead(size_t nMessages) {
1135     // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
1136     auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1137     auto writePtr = mWritePtr->load(std::memory_order_acquire);
1138     /*
1139      * If the flavor is unsynchronized, it is possible that a write overflow may
1140      * have occured between beginRead() and commitRead().
1141      */
1142     if (writePtr - readPtr > mDesc->getSize()) {
1143         mReadPtr->store(writePtr, std::memory_order_release);
1144         return false;
1145     }
1146 
1147     size_t nBytesRead = nMessages * sizeof(T);
1148     readPtr += nBytesRead;
1149     mReadPtr->store(readPtr, std::memory_order_release);
1150     return true;
1151 }
1152 
1153 template <typename T, MQFlavor flavor>
getQuantumSize()1154 size_t MessageQueue<T, flavor>::getQuantumSize() const {
1155     return mDesc->getQuantum();
1156 }
1157 
1158 template <typename T, MQFlavor flavor>
getQuantumCount()1159 size_t MessageQueue<T, flavor>::getQuantumCount() const {
1160     return mDesc->getSize() / mDesc->getQuantum();
1161 }
1162 
1163 template <typename T, MQFlavor flavor>
isValid()1164 bool MessageQueue<T, flavor>::isValid() const {
1165     return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1166 }
1167 
1168 template <typename T, MQFlavor flavor>
mapGrantorDescr(uint32_t grantorIdx)1169 void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
1170     const native_handle_t* handle = mDesc->handle();
1171     auto grantors = mDesc->grantors();
1172     if ((handle == nullptr) || (grantorIdx >= grantors.size())) {
1173         return nullptr;
1174     }
1175 
1176     int fdIndex = grantors[grantorIdx].fdIndex;
1177     /*
1178      * Offset for mmap must be a multiple of PAGE_SIZE.
1179      */
1180     int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1181     int mapLength =
1182             grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1183 
1184     void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
1185                          handle->data[fdIndex], mapOffset);
1186     return (address == MAP_FAILED)
1187             ? nullptr
1188             : reinterpret_cast<uint8_t*>(address) +
1189             (grantors[grantorIdx].offset - mapOffset);
1190 }
1191 
1192 template <typename T, MQFlavor flavor>
unmapGrantorDescr(void * address,uint32_t grantorIdx)1193 void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
1194                                                 uint32_t grantorIdx) {
1195     auto grantors = mDesc->grantors();
1196     if ((address == nullptr) || (grantorIdx >= grantors.size())) {
1197         return;
1198     }
1199 
1200     int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1201     int mapLength =
1202             grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1203     void* baseAddress = reinterpret_cast<uint8_t*>(address) -
1204             (grantors[grantorIdx].offset - mapOffset);
1205     if (baseAddress) munmap(baseAddress, mapLength);
1206 }
1207 
1208 }  // namespace hardware
1209 }  // namespace android
1210 #endif  // HIDL_MQ_H
1211