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