1 //
2 // Copyright 2018 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 __VTS_RESOURCE_VTSFMQDRIVER_H
18 #define __VTS_RESOURCE_VTSFMQDRIVER_H
19
20 #include <mutex>
21 #include <string>
22 #include <unordered_map>
23
24 #include <android-base/logging.h>
25 #include <fmq/MessageQueue.h>
26
27 using android::hardware::kSynchronizedReadWrite;
28 using android::hardware::kUnsynchronizedWrite;
29 using android::hardware::MessageQueue;
30 using android::hardware::MQDescriptorSync;
31 using android::hardware::MQDescriptorUnsync;
32
33 using namespace std;
34 using QueueId = int;
35
36 static constexpr const int kInvalidQueueId = -1;
37
38 namespace android {
39 namespace vts {
40
41 // struct to store queue information.
42 struct QueueInfo {
43 // type of data in the queue.
44 string queue_data_type;
45 // flavor of the queue (sync or unsync).
46 hardware::MQFlavor queue_flavor;
47 // pointer to the actual queue object.
48 shared_ptr<void> queue_object;
49 };
50
51 // A fast message queue class that manages all fast message queues created
52 // on the target side. Reader and writer use their id to read from and write
53 // into the queue.
54 // Example:
55 // VtsFmqDriver manager;
56 // // creates one reader and one writer.
57 // QueueId writer_id =
58 // manager.CreateFmq<uint16_t, kSynchronizedReadWrite>(2048, false);
59 // QueueId reader_id =
60 // manager.CreateFmq<uint16_t, kSynchronizedReadWrite>(writer_id);
61 // // write some data
62 // uint16_t write_data[5] {1, 2, 3, 4, 5};
63 // manager.WriteFmq<uint16_t, kSynchronizedReadWrite>(
64 // writer_id, write_data, 5);
65 // // read the same data back
66 // uint16_t read_data[5];
67 // manager.ReadFmq<uint16_t, kSynchronizedReadWrite>(
68 // reader_id, read_data, 5);
69 class VtsFmqDriver {
70 public:
71 // Constructor to initialize a Fast Message Queue (FMQ) manager.
VtsFmqDriver()72 VtsFmqDriver() {}
73
74 // Destructor to clean up the class.
~VtsFmqDriver()75 ~VtsFmqDriver() {
76 // Clears objects in the map.
77 fmq_map_.clear();
78 }
79
80 // Creates a brand new FMQ, i.e. the "first message queue object".
81 //
82 // @param data_type type of data in the queue. This information is stored
83 // in the driver to verify type later.
84 // @param queue_size number of elements in the queue.
85 // @param blocking whether to enable blocking within the queue.
86 //
87 // @return message queue object id associated with the caller on success,
88 // kInvalidQueueId on failure.
89 template <typename T, hardware::MQFlavor flavor>
90 QueueId CreateFmq(const string& data_type, size_t queue_size, bool blocking);
91
92 // Creates a new FMQ object based on an existing message queue
93 // (Using queue_id assigned by fmq_driver.).
94 //
95 // @param data_type type of data in the queue. This information is stored
96 // in the driver to verify type later.
97 // @param queue_id identifies the message queue object.
98 // @param reset_pointers whether to reset read and write pointers.
99 //
100 // @return message queue object id associated with the caller on success,
101 // kInvalidQueueId on failure.
102 template <typename T, hardware::MQFlavor flavor>
103 QueueId CreateFmq(const string& data_type, QueueId queue_id,
104 bool reset_pointers = true);
105
106 // Creates a new FMQ object based on an existing message queue
107 // (Using queue descriptor.).
108 // This method will reset read/write pointers in the new queue object.
109 //
110 // @param data_type type of data in the queue. This information is
111 // stored in the driver to verify type later.
112 // @param queue_descriptor pointer to descriptor of an existing queue.
113 //
114 // @return message queue object id associated with the caller on success,
115 // kInvalidQueueId on failure.
116 template <typename T, hardware::MQFlavor flavor>
117 QueueId CreateFmq(const string& data_type, size_t queue_descriptor);
118
119 // Reads data_size items from FMQ (no blocking at all).
120 //
121 // @param data_type type of data in the queue. This information is verified
122 // by the driver before calling the API on FMQ.
123 // @param queue_id identifies the message queue object.
124 // @param data pointer to the start of data to be filled.
125 // @param data_size number of items to read.
126 //
127 // @return true if no error happens when reading from FMQ,
128 // false otherwise.
129 template <typename T, hardware::MQFlavor flavor>
130 bool ReadFmq(const string& data_type, QueueId queue_id, T* data,
131 size_t data_size);
132
133 // Reads data_size items from FMQ, block if there is not enough data to
134 // read.
135 // This method can only be called if blocking=true on creation of the "first
136 // message queue object" of the FMQ.
137 //
138 // @param data_type type of data in the queue. This information is
139 // verified by the driver before calling the API on FMQ.
140 // @param queue_id identifies the message queue object.
141 // @param data pointer to the start of data to be filled.
142 // @param data_size number of items to read.
143 // @param time_out_nanos wait time when blocking.
144 //
145 // Returns: true if no error happens when reading from FMQ,
146 // false otherwise.
147 template <typename T, hardware::MQFlavor flavor>
148 bool ReadFmqBlocking(const string& data_type, QueueId queue_id, T* data,
149 size_t data_size, int64_t time_out_nanos);
150
151 // Reads data_size items from FMQ, possibly block on other queues.
152 //
153 // @param data_type type of data in the queue. This information is
154 // verified by the driver before calling the API
155 // on FMQ.
156 // @param queue_id identifies the message queue object.
157 // @param data pointer to the start of data to be filled.
158 // @param data_size number of items to read.
159 // @param read_notification notification bits to set when finish reading.
160 // @param write_notification notification bits to wait on when blocking.
161 // Read will fail if this argument is 0.
162 // @param time_out_nanos wait time when blocking.
163 // @param event_flag_word event flag word shared by multiple queues.
164 //
165 // @return true if no error happens when reading from FMQ,
166 // false otherwise.
167 template <typename T, hardware::MQFlavor flavor>
168 bool ReadFmqBlocking(const string& data_type, QueueId queue_id, T* data,
169 size_t data_size, uint32_t read_notification,
170 uint32_t write_notification, int64_t time_out_nanos,
171 atomic<uint32_t>* event_flag_word);
172
173 // Writes data_size items to FMQ (no blocking at all).
174 //
175 // @param data_type type of data in the queue. This information is verified
176 // by the driver before calling the API on FMQ.
177 // @param queue_id identifies the message queue object.
178 // @param data pointer to the start of data to be written.
179 // @param data_size number of items to write.
180 //
181 // @return true if no error happens when writing to FMQ,
182 // false otherwise.
183 template <typename T, hardware::MQFlavor flavor>
184 bool WriteFmq(const string& data_type, QueueId queue_id, T* data,
185 size_t data_size);
186
187 // Writes data_size items to FMQ, block if there is not enough space in
188 // the queue.
189 // This method can only be called if blocking=true on creation of the "first
190 // message queue object" of the FMQ.
191 //
192 // @param data_type type of data in the queue. This information is
193 // verified
194 // by the driver before calling the API on FMQ.
195 // @param queue_id identifies the message queue object.
196 // @param data pointer to the start of data to be written.
197 // @param data_size number of items to write.
198 // @param time_out_nanos wait time when blocking.
199 //
200 // @returns true if no error happens when writing to FMQ,
201 // false otherwise
202 template <typename T, hardware::MQFlavor flavor>
203 bool WriteFmqBlocking(const string& data_type, QueueId queue_id, T* data,
204 size_t data_size, int64_t time_out_nanos);
205
206 // Writes data_size items to FMQ, possibly block on other queues.
207 //
208 // @param data_type type of data in the queue. This information is
209 // verified by the driver before calling the API
210 // on FMQ.
211 // @param queue_id identifies the message queue object.
212 // @param data pointer to the start of data to be written.
213 // @param data_size number of items to write.
214 // @param read_notification notification bits to wait on when blocking.
215 // Write will fail if this argument is 0.
216 // @param write_notification notification bits to set when finish writing.
217 // @param time_out_nanos wait time when blocking.
218 // @param event_flag_word event flag word shared by multiple queues.
219 //
220 // @return true if no error happens when writing to FMQ,
221 // false otherwise.
222 template <typename T, hardware::MQFlavor flavor>
223 bool WriteFmqBlocking(const string& data_type, QueueId queue_id, T* data,
224 size_t data_size, uint32_t read_notification,
225 uint32_t write_notification, int64_t time_out_nanos,
226 atomic<uint32_t>* event_flag_word);
227
228 // Gets space available to write in the queue.
229 //
230 // @param data_type type of data in the queue. This information is
231 // verified by the driver before calling the API on FMQ.
232 // @param queue_id identifies the message queue object.
233 // @param result pointer to the result. Use pointer to store result because
234 // the return value signals if the queue is found correctly.
235 //
236 // @return true if queue is found and type matches, and puts actual result in
237 // result pointer,
238 // false otherwise.
239 template <typename T, hardware::MQFlavor flavor>
240 bool AvailableToWrite(const string& data_type, QueueId queue_id,
241 size_t* result);
242
243 // Gets number of items available to read in the queue.
244 //
245 // @param data_type type of data in the queue. This information is
246 // verified by the driver before calling the API on FMQ.
247 // @param queue_id identifies the message queue object.
248 // @param result pointer to the result. Use pointer to store result because
249 // the return value signals if the queue is found correctly.
250 //
251 // @return true if queue is found and type matches, and puts actual result in
252 // result pointer,
253 // false otherwise.
254 template <typename T, hardware::MQFlavor flavor>
255 bool AvailableToRead(const string& data_type, QueueId queue_id,
256 size_t* result);
257
258 // Gets size of item in the queue.
259 //
260 // @param data_type type of data in the queue. This information is
261 // verified by the driver before calling the API on FMQ.
262 // @param queue_id identifies the message queue object.
263 // @param result pointer to the result. Use pointer to store result because
264 // the return value signals if the queue is found correctly.
265 //
266 // @return true if queue is found and type matches, and puts actual result in
267 // result pointer,
268 // false otherwise.
269 template <typename T, hardware::MQFlavor flavor>
270 bool GetQuantumSize(const string& data_type, QueueId queue_id,
271 size_t* result);
272
273 // Gets number of items that fit in the queue.
274 //
275 // @param data_type type of data in the queue. This information is
276 // verified by the driver before calling the API on FMQ.
277 // @param queue_id identifies the message queue object.
278 // @param result pointer to the result. Use pointer to store result because
279 // the return value signals if the queue is found correctly.
280 //
281 // @return true if queue is found and type matches, and puts actual result in
282 // result pointer,
283 // false otherwise.
284 template <typename T, hardware::MQFlavor flavor>
285 bool GetQuantumCount(const string& data_type, QueueId queue_id,
286 size_t* result);
287
288 // Checks if the queue associated with queue_id is valid.
289 //
290 // @param data_type type of data in the queue. This information is
291 // verified by the driver before calling the API on FMQ.
292 // @param queue_id identifies the message queue object.
293 //
294 // @return true if the queue object is valid, false otherwise.
295 template <typename T, hardware::MQFlavor flavor>
296 bool IsValid(const string& data_type, QueueId queue_id);
297
298 // Gets event flag word of the queue, which allows multiple queues
299 // to communicate (i.e. blocking).
300 // The returned event flag word can be passed into readBlocking() and
301 // writeBlocking() to achieve blocking among multiple queues.
302 //
303 // @param data_type type of data in the queue. This information is
304 // verified by the driver before calling the API on FMQ.
305 // @param queue_id identifies the message queue object.
306 // @param result pointer to the result. Use pointer to store result because
307 // the return value signals if the queue is found correctly.
308 //
309 // @return true if queue is found and type matches, and puts actual result in
310 // result pointer,
311 // false otherwise.
312 template <typename T, hardware::MQFlavor flavor>
313 bool GetEventFlagWord(const string& data_type, QueueId queue_id,
314 atomic<uint32_t>** result);
315
316 // Gets the address of queue descriptor in memory. This function is called by
317 // driver_manager to preprocess arguments that are FMQs.
318 //
319 // @param data_type type of data in the queue. This information is
320 // verified by the driver before calling the API on FMQ.
321 // @param queue_id identifies the message queue object.
322 // @param result pointer to store result.
323 //
324 // @return true if queue is found, and type matches, and puts actual result in
325 // result pointer,
326 // false otherwise.
327 template <typename T, hardware::MQFlavor flavor>
328 bool GetQueueDescAddress(const string& data_type, QueueId queue_id,
329 size_t* result);
330
331 private:
332 // Finds the queue in the map based on the input queue ID.
333 //
334 // @param data_type type of data in the queue. This function verifies this
335 // information.
336 // @param queue_id identifies the message queue object.
337 //
338 // @return the pointer to message queue object,
339 // nullptr if queue ID is invalid or queue type is misspecified.
340 template <typename T, hardware::MQFlavor flavor>
341 MessageQueue<T, flavor>* FindQueue(const string& data_type, QueueId queue_id);
342
343 // Inserts a FMQ object into the map, along with its type of data and queue
344 // flavor. This function ensures only one thread is inserting queue into the
345 // map at once.
346 //
347 // @param data_type type of data in the queue. This information is stored
348 // in the driver.
349 // @param queue_object a shared pointer to MessageQueue.
350 //
351 // @return id associated with the queue.
352 template <typename T, hardware::MQFlavor flavor>
353 QueueId InsertQueue(const string& data_type,
354 shared_ptr<MessageQueue<T, flavor>> queue_object);
355
356 // a hashtable to keep track of all ongoing FMQ's.
357 // The key of the hashtable is the queue ID.
358 // The value of the hashtable is a smart pointer to message queue object
359 // information struct associated with the queue ID.
360 unordered_map<QueueId, unique_ptr<QueueInfo>> fmq_map_;
361
362 // a mutex to ensure mutual exclusion of operations on fmq_map_
363 mutex map_mutex_;
364 };
365
366 // Implementations follow, because all the methods are template methods.
367 template <typename T, hardware::MQFlavor flavor>
CreateFmq(const string & data_type,size_t queue_size,bool blocking)368 QueueId VtsFmqDriver::CreateFmq(const string& data_type, size_t queue_size,
369 bool blocking) {
370 shared_ptr<MessageQueue<T, flavor>> new_queue(
371 new (std::nothrow) MessageQueue<T, flavor>(queue_size, blocking));
372 return InsertQueue<T, flavor>(data_type, new_queue);
373 }
374
375 template <typename T, hardware::MQFlavor flavor>
CreateFmq(const string & data_type,QueueId queue_id,bool reset_pointers)376 QueueId VtsFmqDriver::CreateFmq(const string& data_type, QueueId queue_id,
377 bool reset_pointers) {
378 MessageQueue<T, flavor>* queue_object =
379 FindQueue<T, flavor>(data_type, queue_id);
380 const hardware::MQDescriptor<T, flavor>* descriptor = queue_object->getDesc();
381 if (descriptor == nullptr) {
382 LOG(ERROR) << "FMQ Driver: cannot find descriptor for the specified "
383 << "Fast Message Queue with ID " << queue_id << ".";
384 return kInvalidQueueId;
385 }
386
387 shared_ptr<MessageQueue<T, flavor>> new_queue(
388 new (std::nothrow) MessageQueue<T, flavor>(*descriptor, reset_pointers));
389 return InsertQueue<T, flavor>(data_type, new_queue);
390 }
391
392 template <typename T, hardware::MQFlavor flavor>
CreateFmq(const string & data_type,size_t queue_desc_addr)393 QueueId VtsFmqDriver::CreateFmq(const string& data_type,
394 size_t queue_desc_addr) {
395 // Cast the address back to a descriptor object.
396 hardware::MQDescriptor<T, flavor>* descriptor_addr =
397 reinterpret_cast<hardware::MQDescriptor<T, flavor>*>(queue_desc_addr);
398 shared_ptr<MessageQueue<T, flavor>> new_queue(
399 new (std::nothrow) MessageQueue<T, flavor>(*descriptor_addr));
400 // Need to manually delete this pointer because HAL driver allocates it.
401 delete descriptor_addr;
402
403 return InsertQueue<T, flavor>(data_type, new_queue);
404 }
405
406 template <typename T, hardware::MQFlavor flavor>
ReadFmq(const string & data_type,QueueId queue_id,T * data,size_t data_size)407 bool VtsFmqDriver::ReadFmq(const string& data_type, QueueId queue_id, T* data,
408 size_t data_size) {
409 MessageQueue<T, flavor>* queue_object =
410 FindQueue<T, flavor>(data_type, queue_id);
411 if (queue_object == nullptr) return false;
412 return queue_object->read(data, data_size);
413 }
414
415 template <typename T, hardware::MQFlavor flavor>
ReadFmqBlocking(const string & data_type,QueueId queue_id,T * data,size_t data_size,int64_t time_out_nanos)416 bool VtsFmqDriver::ReadFmqBlocking(const string& data_type, QueueId queue_id,
417 T* data, size_t data_size,
418 int64_t time_out_nanos) {
419 if (flavor == kUnsynchronizedWrite) {
420 LOG(ERROR) << "FMQ Driver: blocking read is not allowed in "
421 << "unsynchronized queue.";
422 return false;
423 }
424
425 MessageQueue<T, kSynchronizedReadWrite>* queue_object =
426 FindQueue<T, kSynchronizedReadWrite>(data_type, queue_id);
427 if (queue_object == nullptr) return false;
428 return queue_object->readBlocking(data, data_size, time_out_nanos);
429 }
430
431 template <typename T, hardware::MQFlavor flavor>
ReadFmqBlocking(const string & data_type,QueueId queue_id,T * data,size_t data_size,uint32_t read_notification,uint32_t write_notification,int64_t time_out_nanos,atomic<uint32_t> * event_flag_word)432 bool VtsFmqDriver::ReadFmqBlocking(const string& data_type, QueueId queue_id,
433 T* data, size_t data_size,
434 uint32_t read_notification,
435 uint32_t write_notification,
436 int64_t time_out_nanos,
437 atomic<uint32_t>* event_flag_word) {
438 if (flavor == kUnsynchronizedWrite) {
439 LOG(ERROR) << "FMQ Driver: blocking read is not allowed in "
440 << "unsynchronized queue.";
441 return false;
442 }
443
444 hardware::EventFlag* ef_group = nullptr;
445 status_t status;
446 // create an event flag out of the event flag word
447 status = hardware::EventFlag::createEventFlag(event_flag_word, &ef_group);
448 if (status != NO_ERROR) { // check status
449 LOG(ERROR) << "FMQ Driver: cannot create event flag with the specified "
450 << "event flag word.";
451 return false;
452 }
453
454 MessageQueue<T, kSynchronizedReadWrite>* queue_object =
455 FindQueue<T, kSynchronizedReadWrite>(data_type, queue_id);
456 if (queue_object == nullptr) return false;
457 return queue_object->readBlocking(data, data_size, read_notification,
458 write_notification, time_out_nanos,
459 ef_group);
460 }
461
462 template <typename T, hardware::MQFlavor flavor>
WriteFmq(const string & data_type,QueueId queue_id,T * data,size_t data_size)463 bool VtsFmqDriver::WriteFmq(const string& data_type, QueueId queue_id, T* data,
464 size_t data_size) {
465 MessageQueue<T, flavor>* queue_object =
466 FindQueue<T, flavor>(data_type, queue_id);
467 if (queue_object == nullptr) return false;
468 return queue_object->write(data, data_size);
469 }
470
471 template <typename T, hardware::MQFlavor flavor>
WriteFmqBlocking(const string & data_type,QueueId queue_id,T * data,size_t data_size,int64_t time_out_nanos)472 bool VtsFmqDriver::WriteFmqBlocking(const string& data_type, QueueId queue_id,
473 T* data, size_t data_size,
474 int64_t time_out_nanos) {
475 if (flavor == kUnsynchronizedWrite) {
476 LOG(ERROR) << "FMQ Driver: blocking write is not allowed in "
477 << "unsynchronized queue.";
478 return false;
479 }
480
481 MessageQueue<T, kSynchronizedReadWrite>* queue_object =
482 FindQueue<T, kSynchronizedReadWrite>(data_type, queue_id);
483 if (queue_object == nullptr) return false;
484 return queue_object->writeBlocking(data, data_size, time_out_nanos);
485 }
486
487 template <typename T, hardware::MQFlavor flavor>
WriteFmqBlocking(const string & data_type,QueueId queue_id,T * data,size_t data_size,uint32_t read_notification,uint32_t write_notification,int64_t time_out_nanos,atomic<uint32_t> * event_flag_word)488 bool VtsFmqDriver::WriteFmqBlocking(const string& data_type, QueueId queue_id,
489 T* data, size_t data_size,
490 uint32_t read_notification,
491 uint32_t write_notification,
492 int64_t time_out_nanos,
493 atomic<uint32_t>* event_flag_word) {
494 if (flavor == kUnsynchronizedWrite) {
495 LOG(ERROR) << "FMQ Driver: blocking write is not allowed in "
496 << "unsynchronized queue.";
497 return false;
498 }
499
500 hardware::EventFlag* ef_group = nullptr;
501 status_t status;
502 // create an event flag out of the event flag word
503 status = hardware::EventFlag::createEventFlag(event_flag_word, &ef_group);
504 if (status != NO_ERROR) { // check status
505 LOG(ERROR) << "FMQ Driver: cannot create event flag with the specified "
506 << "event flag word.";
507 return false;
508 }
509
510 MessageQueue<T, kSynchronizedReadWrite>* queue_object =
511 FindQueue<T, kSynchronizedReadWrite>(data_type, queue_id);
512 if (queue_object == nullptr) return false;
513 return queue_object->writeBlocking(data, data_size, read_notification,
514 write_notification, time_out_nanos,
515 ef_group);
516 }
517
518 template <typename T, hardware::MQFlavor flavor>
AvailableToWrite(const string & data_type,QueueId queue_id,size_t * result)519 bool VtsFmqDriver::AvailableToWrite(const string& data_type, QueueId queue_id,
520 size_t* result) {
521 MessageQueue<T, flavor>* queue_object =
522 FindQueue<T, flavor>(data_type, queue_id);
523 if (queue_object == nullptr) return false;
524 *result = queue_object->availableToWrite();
525 return true;
526 }
527
528 template <typename T, hardware::MQFlavor flavor>
AvailableToRead(const string & data_type,QueueId queue_id,size_t * result)529 bool VtsFmqDriver::AvailableToRead(const string& data_type, QueueId queue_id,
530 size_t* result) {
531 MessageQueue<T, flavor>* queue_object =
532 FindQueue<T, flavor>(data_type, queue_id);
533 if (queue_object == nullptr) return false;
534 *result = queue_object->availableToRead();
535 return true;
536 }
537
538 template <typename T, hardware::MQFlavor flavor>
GetQuantumSize(const string & data_type,QueueId queue_id,size_t * result)539 bool VtsFmqDriver::GetQuantumSize(const string& data_type, QueueId queue_id,
540 size_t* result) {
541 MessageQueue<T, flavor>* queue_object =
542 FindQueue<T, flavor>(data_type, queue_id);
543 if (queue_object == nullptr) return false;
544 *result = queue_object->getQuantumSize();
545 return true;
546 }
547
548 template <typename T, hardware::MQFlavor flavor>
GetQuantumCount(const string & data_type,QueueId queue_id,size_t * result)549 bool VtsFmqDriver::GetQuantumCount(const string& data_type, QueueId queue_id,
550 size_t* result) {
551 MessageQueue<T, flavor>* queue_object =
552 FindQueue<T, flavor>(data_type, queue_id);
553 if (queue_object == nullptr) return false;
554 *result = queue_object->getQuantumCount();
555 return true;
556 }
557
558 template <typename T, hardware::MQFlavor flavor>
IsValid(const string & data_type,QueueId queue_id)559 bool VtsFmqDriver::IsValid(const string& data_type, QueueId queue_id) {
560 MessageQueue<T, flavor>* queue_object =
561 FindQueue<T, flavor>(data_type, queue_id);
562 if (queue_object == nullptr) return false;
563 return queue_object->isValid();
564 }
565
566 template <typename T, hardware::MQFlavor flavor>
GetEventFlagWord(const string & data_type,QueueId queue_id,atomic<uint32_t> ** result)567 bool VtsFmqDriver::GetEventFlagWord(const string& data_type, QueueId queue_id,
568 atomic<uint32_t>** result) {
569 MessageQueue<T, flavor>* queue_object =
570 FindQueue<T, flavor>(data_type, queue_id);
571 if (queue_object == nullptr) return false;
572 *result = queue_object->getEventFlagWord();
573 return true;
574 }
575
576 template <typename T, hardware::MQFlavor flavor>
GetQueueDescAddress(const string & data_type,QueueId queue_id,size_t * result)577 bool VtsFmqDriver::GetQueueDescAddress(const string& data_type,
578 QueueId queue_id, size_t* result) {
579 MessageQueue<T, flavor>* queue_object =
580 FindQueue<T, flavor>(data_type, queue_id);
581 if (queue_object == nullptr) return false;
582 *result = reinterpret_cast<size_t>(queue_object->getDesc());
583 return true;
584 }
585
586 template <typename T, hardware::MQFlavor flavor>
FindQueue(const string & data_type,QueueId queue_id)587 MessageQueue<T, flavor>* VtsFmqDriver::FindQueue(const string& data_type,
588 QueueId queue_id) {
589 map_mutex_.lock(); // Ensure mutual exclusion.
590 auto iterator = fmq_map_.find(queue_id);
591 if (iterator == fmq_map_.end()) { // queue not found
592 LOG(ERROR) << "FMQ Driver: cannot find Fast Message Queue with ID "
593 << queue_id;
594 return nullptr;
595 }
596
597 QueueInfo* queue_info = (iterator->second).get();
598 if (queue_info->queue_data_type != data_type) { // queue data type incorrect
599 LOG(ERROR) << "FMQ Driver: caller specified data type " << data_type
600 << " doesn't match with the data type "
601 << queue_info->queue_data_type << " stored in driver.";
602 return nullptr;
603 }
604
605 if (queue_info->queue_flavor != flavor) { // queue flavor incorrect
606 LOG(ERROR) << "FMQ Driver: caller specified flavor " << flavor
607 << "doesn't match with the stored queue flavor "
608 << queue_info->queue_flavor << ".";
609 return nullptr;
610 }
611
612 // type check passes, extract queue from the struct
613 shared_ptr<MessageQueue<T, flavor>> queue_object =
614 static_pointer_cast<MessageQueue<T, flavor>>(queue_info->queue_object);
615 MessageQueue<T, flavor>* result = queue_object.get();
616 map_mutex_.unlock();
617 return result;
618 }
619
620 template <typename T, hardware::MQFlavor flavor>
InsertQueue(const string & data_type,shared_ptr<MessageQueue<T,flavor>> queue_object)621 QueueId VtsFmqDriver::InsertQueue(
622 const string& data_type, shared_ptr<MessageQueue<T, flavor>> queue_object) {
623 if (queue_object == nullptr) {
624 LOG(ERROR) << "FMQ Driver Error: Failed to create a FMQ "
625 << "using FMQ constructor.";
626 return kInvalidQueueId;
627 }
628 // Create a struct to store queue object, type of data, and
629 // queue flavor.
630 unique_ptr<QueueInfo> new_queue_info(new QueueInfo{
631 string(data_type), flavor, static_pointer_cast<void>(queue_object)});
632 map_mutex_.lock();
633 size_t new_queue_id = fmq_map_.size();
634 fmq_map_.emplace(new_queue_id, move(new_queue_info));
635 map_mutex_.unlock();
636 return new_queue_id;
637 }
638
639 } // namespace vts
640 } // namespace android
641 #endif //__VTS_RESOURCE_VTSFMQDRIVER_H
642