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 _FMSGQ_DESCRIPTOR_H
18 #define _FMSGQ_DESCRIPTOR_H
19 
20 #include <android-base/macros.h>
21 #include <cutils/native_handle.h>
22 #include <hidl/HidlInternal.h>
23 #include <hidl/HidlSupport.h>
24 
25 namespace android {
26 namespace hardware {
27 
28 typedef uint64_t RingBufferPosition;
29 
30 struct GrantorDescriptor {
31     uint32_t flags __attribute__ ((aligned(4)));
32     uint32_t fdIndex __attribute__ ((aligned(4)));
33     uint32_t offset __attribute__ ((aligned(4)));
34     uint64_t extent __attribute__ ((aligned(8)));
35 };
36 
37 static_assert(offsetof(GrantorDescriptor, flags) == 0, "wrong offset");
38 static_assert(offsetof(GrantorDescriptor, fdIndex) == 4, "wrong offset");
39 static_assert(offsetof(GrantorDescriptor, offset) == 8, "wrong offset");
40 static_assert(offsetof(GrantorDescriptor, extent) == 16, "wrong offset");
41 static_assert(sizeof(GrantorDescriptor) == 24, "wrong size");
42 static_assert(__alignof(GrantorDescriptor) == 8, "wrong alignment");
43 
44 enum MQFlavor : uint32_t {
45   /*
46    * kSynchronizedReadWrite represents the wait-free synchronized flavor of the
47    * FMQ. It is intended to be have a single reader and single writer.
48    * Attempts to overflow/underflow returns a failure.
49    */
50   kSynchronizedReadWrite = 0x01,
51   /*
52    * kUnsynchronizedWrite represents the flavor of FMQ where writes always
53    * succeed. This flavor allows one writer and many readers. A read operation
54    * can detect an overwrite and reset the read counter.
55    */
56   kUnsynchronizedWrite = 0x02
57 };
58 
59 template <typename T, MQFlavor flavor>
60 struct MQDescriptor {
61     MQDescriptor(
62             const std::vector<GrantorDescriptor>& grantors,
63             native_handle_t* nHandle, size_t size);
64 
65     MQDescriptor(size_t bufferSize, native_handle_t* nHandle,
66                  size_t messageSize, bool configureEventFlag = false);
67 
68     MQDescriptor();
69     ~MQDescriptor();
70 
71     explicit MQDescriptor(const MQDescriptor &other);
72     MQDescriptor &operator=(const MQDescriptor &other) = delete;
73 
74     size_t getSize() const;
75 
76     size_t getQuantum() const;
77 
78     int32_t getFlags() const;
79 
isHandleValidMQDescriptor80     bool isHandleValid() const { return mHandle != nullptr; }
countGrantorsMQDescriptor81     size_t countGrantors() const { return mGrantors.size(); }
82 
grantorsMQDescriptor83     inline const ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() const {
84         return mGrantors;
85     }
86 
grantorsMQDescriptor87     inline ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() {
88         return mGrantors;
89     }
90 
handleMQDescriptor91     inline const ::native_handle_t *handle() const {
92         return mHandle;
93     }
94 
handleMQDescriptor95     inline ::native_handle_t *handle() {
96         return mHandle;
97     }
98 
99     static const size_t kOffsetOfGrantors;
100     static const size_t kOffsetOfHandle;
101     enum GrantorType : int { READPTRPOS = 0, WRITEPTRPOS, DATAPTRPOS, EVFLAGWORDPOS };
102 
103     /*
104      * There should at least be GrantorDescriptors for the read counter, write
105      * counter and data buffer. A GrantorDescriptor for an EventFlag word is
106      * not required if there is no need for blocking FMQ operations.
107      */
108     static constexpr int32_t kMinGrantorCount = DATAPTRPOS + 1;
109 
110     /*
111      * Minimum number of GrantorDescriptors required if EventFlag support is
112      * needed for blocking FMQ operations.
113      */
114     static constexpr int32_t kMinGrantorCountForEvFlagSupport = EVFLAGWORDPOS + 1;
115 
116     //TODO(b/34160777) Identify a better solution that supports remoting.
alignToWordBoundaryMQDescriptor117     static inline size_t alignToWordBoundary(size_t length) {
118         constexpr size_t kAlignmentSize = 64;
119         if (kAlignmentSize % __WORDSIZE != 0) {
120             details::logAlwaysFatal("Incompatible word size");
121         }
122 
123         /*
124          * Check if alignment to word boundary would cause an overflow.
125          */
126         if (length > SIZE_MAX - kAlignmentSize/8 + 1) {
127             details::logAlwaysFatal("Queue size too large");
128         }
129 
130         return (length + kAlignmentSize/8 - 1) & ~(kAlignmentSize/8 - 1U);
131     }
132 
isAlignedToWordBoundaryMQDescriptor133     static inline size_t isAlignedToWordBoundary(size_t offset) {
134         constexpr size_t kAlignmentSize = 64;
135         return (offset & (kAlignmentSize/8 - 1)) == 0;
136     }
137 private:
138     ::android::hardware::hidl_vec<GrantorDescriptor> mGrantors;
139     ::android::hardware::details::hidl_pointer<native_handle_t> mHandle;
140     uint32_t mQuantum;
141     uint32_t mFlags;
142 };
143 
144 template<typename T, MQFlavor flavor>
145 const size_t MQDescriptor<T, flavor>::kOffsetOfGrantors = offsetof(MQDescriptor, mGrantors);
146 
147 template<typename T, MQFlavor flavor>
148 const size_t MQDescriptor<T, flavor>::kOffsetOfHandle = offsetof(MQDescriptor, mHandle);
149 
150 /*
151  * MQDescriptorSync will describe the wait-free synchronized
152  * flavor of FMQ.
153  */
154 template<typename T>
155 using MQDescriptorSync = MQDescriptor<T, kSynchronizedReadWrite>;
156 
157 /*
158  * MQDescriptorUnsync will describe the unsynchronized write
159  * flavor of FMQ.
160  */
161 template<typename T>
162 using MQDescriptorUnsync = MQDescriptor<T, kUnsynchronizedWrite>;
163 
164 template<typename T, MQFlavor flavor>
MQDescriptor(const std::vector<GrantorDescriptor> & grantors,native_handle_t * nhandle,size_t size)165 MQDescriptor<T, flavor>::MQDescriptor(
166         const std::vector<GrantorDescriptor>& grantors,
167         native_handle_t* nhandle,
168         size_t size)
169     : mHandle(nhandle),
170       mQuantum(size),
171       mFlags(flavor) {
172     mGrantors.resize(grantors.size());
173     for (size_t i = 0; i < grantors.size(); ++i) {
174         if (isAlignedToWordBoundary(grantors[i].offset) == false) {
175             details::logAlwaysFatal("Grantor offsets need to be aligned");
176         }
177         mGrantors[i] = grantors[i];
178     }
179 }
180 
181 template<typename T, MQFlavor flavor>
MQDescriptor(size_t bufferSize,native_handle_t * nHandle,size_t messageSize,bool configureEventFlag)182 MQDescriptor<T, flavor>::MQDescriptor(size_t bufferSize, native_handle_t *nHandle,
183                                    size_t messageSize, bool configureEventFlag)
184     : mHandle(nHandle), mQuantum(messageSize), mFlags(flavor) {
185     /*
186      * If configureEventFlag is true, allocate an additional spot in mGrantor
187      * for containing the fd and offset for mmapping the EventFlag word.
188      */
189     mGrantors.resize(configureEventFlag? kMinGrantorCountForEvFlagSupport : kMinGrantorCount);
190 
191     size_t memSize[] = {
192         sizeof(RingBufferPosition),  /* memory to be allocated for read pointer counter */
193         sizeof(RingBufferPosition),  /* memory to be allocated for write pointer counter */
194         bufferSize,                  /* memory to be allocated for data buffer */
195         sizeof(std::atomic<uint32_t>)/* memory to be allocated for EventFlag word */
196     };
197 
198     /*
199      * Create a default grantor descriptor for read, write pointers and
200      * the data buffer. fdIndex parameter is set to 0 by default and
201      * the offset for each grantor is contiguous.
202      */
203     for (size_t grantorPos = 0, offset = 0;
204          grantorPos < mGrantors.size();
205          offset += memSize[grantorPos++]) {
206         mGrantors[grantorPos] = {
207             0 /* grantor flags */,
208             0 /* fdIndex */,
209             static_cast<uint32_t>(alignToWordBoundary(offset)),
210             memSize[grantorPos]
211         };
212     }
213 }
214 
215 template<typename T, MQFlavor flavor>
MQDescriptor(const MQDescriptor<T,flavor> & other)216 MQDescriptor<T, flavor>::MQDescriptor(const MQDescriptor<T, flavor> &other)
217     : mGrantors(other.mGrantors),
218       mHandle(nullptr),
219       mQuantum(other.mQuantum),
220       mFlags(other.mFlags) {
221     if (other.mHandle != nullptr) {
222         mHandle = native_handle_create(
223                 other.mHandle->numFds, other.mHandle->numInts);
224 
225         for (int i = 0; i < other.mHandle->numFds; ++i) {
226             mHandle->data[i] = dup(other.mHandle->data[i]);
227         }
228 
229         memcpy(&mHandle->data[other.mHandle->numFds],
230                &other.mHandle->data[other.mHandle->numFds],
231                other.mHandle->numInts * sizeof(int));
232     }
233 }
234 
235 template<typename T, MQFlavor flavor>
MQDescriptor()236 MQDescriptor<T, flavor>::MQDescriptor() : MQDescriptor(
237         std::vector<android::hardware::GrantorDescriptor>(),
238         nullptr /* nHandle */,
239         0 /* size */) {}
240 
241 template<typename T, MQFlavor flavor>
~MQDescriptor()242 MQDescriptor<T, flavor>::~MQDescriptor() {
243     if (mHandle != nullptr) {
244         native_handle_close(mHandle);
245         native_handle_delete(mHandle);
246     }
247 }
248 
249 template<typename T, MQFlavor flavor>
getSize()250 size_t MQDescriptor<T, flavor>::getSize() const {
251   return mGrantors[DATAPTRPOS].extent;
252 }
253 
254 template<typename T, MQFlavor flavor>
getQuantum()255 size_t MQDescriptor<T, flavor>::getQuantum() const { return mQuantum; }
256 
257 template<typename T, MQFlavor flavor>
getFlags()258 int32_t MQDescriptor<T, flavor>::getFlags() const { return mFlags; }
259 
260 template<typename T, MQFlavor flavor>
toString(const MQDescriptor<T,flavor> & q)261 std::string toString(const MQDescriptor<T, flavor> &q) {
262     std::string os;
263     if (flavor & kSynchronizedReadWrite) {
264         os += "fmq_sync";
265     }
266     if (flavor & kUnsynchronizedWrite) {
267         os += "fmq_unsync";
268     }
269     os += " {"
270        + toString(q.grantors().size()) + " grantor(s), "
271        + "size = " + toString(q.getSize())
272        + ", .handle = " + toString(q.handle())
273        + ", .quantum = " + toString(q.getQuantum()) + "}";
274     return os;
275 }
276 
277 }  // namespace hardware
278 }  // namespace android
279 
280 #endif  // FMSGQ_DESCRIPTOR_H
281