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