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 LOGD("Waiting for event type 0x%" PRIx16, eventType); 92 while (true) { 93 auto event = mQueue.pop(); 94 LOGD("Got event type 0x%" PRIx16, event.type); 95 ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT) 96 << "Timeout waiting for event " << eventType; 97 memoryFree(event.data); 98 if (event.type == eventType) { 99 break; 100 } 101 } 102 } 103 104 //! Block until the event happens and populate the event data. 105 template <class T> waitForEvent(uint16_t eventType,T * data)106 void waitForEvent(uint16_t eventType, T *data) { 107 static_assert(std::is_trivial<T>::value); 108 LOGD("Waiting for event type 0x%" PRIx16, eventType); 109 while (true) { 110 auto event = mQueue.pop(); 111 LOGD("Got event type 0x%" PRIx16, event.type); 112 ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT) 113 << "Timeout waiting for event " << eventType; 114 if (event.type == eventType) { 115 *data = *(static_cast<T *>(event.data)); 116 memoryFree(event.data); 117 break; 118 } 119 memoryFree(event.data); 120 } 121 } 122 123 //! Flush the queue. flush()124 void flush() { 125 while (!mQueue.empty()) { 126 auto event = mQueue.pop(); 127 memoryFree(event.data); 128 } 129 } 130 131 private: 132 static const size_t kQueueCapacity = 64; 133 FixedSizeBlockingQueue<TestEvent, kQueueCapacity> mQueue; 134 }; 135 136 //! Provide an alias to the TestEventQueue singleton. 137 typedef Singleton<TestEventQueue> TestEventQueueSingleton; 138 139 //! Extern the explicit TestEventQueueSingleton to force non-inline method 140 //! calls. 141 extern template class Singleton<TestEventQueue>; 142 143 } // namespace chre 144 145 #endif // CHRE_SIMULATION_TEST_EVENT_QUEUE_H_ 146