1 /* 2 * Copyright (C) 2021 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 CHRE_SIMULATION_TEST_EVENT_QUEUE_H_ 18 #define CHRE_SIMULATION_TEST_EVENT_QUEUE_H_ 19 20 #include <gtest/gtest.h> 21 22 #include <cinttypes> 23 24 #include "chre/platform/memory.h" 25 #include "chre/util/fixed_size_blocking_queue.h" 26 #include "chre/util/memory.h" 27 #include "chre/util/non_copyable.h" 28 #include "chre/util/singleton.h" 29 #include "test_event.h" 30 31 namespace chre { 32 33 //! A test event type to indicate the test nanoapp has loaded. 34 #define CHRE_EVENT_SIMULATION_TEST_NANOAPP_LOADED \ 35 CHRE_SIMULATION_TEST_EVENT_ID(0) 36 37 //! A test event type to indicate the test has timed out, and should abort. 38 #define CHRE_EVENT_SIMULATION_TEST_TIMEOUT CHRE_SIMULATION_TEST_EVENT_ID(1) 39 40 //! A test event type to indicate the test nanoapp has unloaded. 41 #define CHRE_EVENT_SIMULATION_TEST_NANOAPP_UNLOADED \ 42 CHRE_SIMULATION_TEST_EVENT_ID(2) 43 44 /** 45 * A class that monitors events for the test to consume. 46 * 47 * This class can be used as an execution barrier for the test, i.e. waiting 48 * for a specific event to occur. The barrier is done through the semantics of 49 * CHRE events, and can be used e.g. for nanoapps to redirect incoming events 50 * using pushEvent(). 51 * 52 * The main test thread can then wait for this event using waitForEvent(). 53 * 54 * Note 1) pushEvent() can also be invoked outside the nanoapp, for instance 55 * using deferred system callbacks. 56 * Note 2) The CHRE_EVENT_SIMULATION_TEST_TIMEOUT event type can be used to 57 * abort the test due to a timeout (this usage is recommended in order to avoid 58 * the test framework from stalling). 59 */ 60 class TestEventQueue : public NonCopyable { 61 public: 62 //! Push an event to the queue. pushEvent(uint16_t eventType)63 void pushEvent(uint16_t eventType) { 64 mQueue.push({eventType}); 65 } 66 67 /** 68 * Push an event with data to the queue. 69 * 70 * Note: The data passed to this method must be trivially copyable. It is 71 * recommended to pass a scalar or a struct composed of scalars only. If this 72 * method is used in the test nanoapp handleEvent be careful not to forward 73 * pointers to memory that could be freed by the CHRE framework before the 74 * data is received using @ref waitForEvent. 75 * 76 * @param eventType The type of event. 77 * @param eventData The data to send together with the event, which must not 78 * contain references to dynamically allocated memory. 79 */ 80 template <class T> pushEvent(uint16_t eventType,T eventData)81 void pushEvent(uint16_t eventType, T eventData) { 82 static_assert(std::is_trivial<T>::value); 83 auto ptr = memoryAlloc<T>(); 84 ASSERT_NE(ptr, nullptr); 85 *ptr = eventData; 86 mQueue.push({eventType, static_cast<void *>(ptr)}); 87 } 88 89 //! Block until the event happens. waitForEvent(uint16_t eventType)90 void waitForEvent(uint16_t eventType) { 91 while (true) { 92 auto event = mQueue.pop(); 93 LOGD("Got event type 0x%" PRIx16, eventType); 94 ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT) 95 << "Timeout waiting for event " << eventType; 96 memoryFree(event.data); 97 if (event.type == eventType) { 98 break; 99 } 100 } 101 } 102 103 //! Block until the event happens and populate the event data. 104 template <class T> waitForEvent(uint16_t eventType,T * data)105 void waitForEvent(uint16_t eventType, T *data) { 106 static_assert(std::is_trivial<T>::value); 107 while (true) { 108 auto event = mQueue.pop(); 109 LOGD("Got event type 0x%" PRIx16, eventType); 110 ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT) 111 << "Timeout waiting for event " << eventType; 112 if (event.type == eventType) { 113 *data = *(static_cast<T *>(event.data)); 114 memoryFree(event.data); 115 break; 116 } 117 memoryFree(event.data); 118 } 119 } 120 121 //! Flush the queue. flush()122 void flush() { 123 while (!mQueue.empty()) { 124 auto event = mQueue.pop(); 125 memoryFree(event.data); 126 } 127 } 128 129 private: 130 static const size_t kQueueCapacity = 64; 131 FixedSizeBlockingQueue<TestEvent, kQueueCapacity> mQueue; 132 }; 133 134 //! Provide an alias to the TestEventQueue singleton. 135 typedef Singleton<TestEventQueue> TestEventQueueSingleton; 136 137 //! Extern the explicit TestEventQueueSingleton to force non-inline method 138 //! calls. 139 extern template class Singleton<TestEventQueue>; 140 141 } // namespace chre 142 143 #endif // CHRE_SIMULATION_TEST_EVENT_QUEUE_H_ 144