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_UTIL_H_
18 #define CHRE_SIMULATION_TEST_UTIL_H_
19
20 #include <algorithm>
21 #include <chrono>
22 #include <condition_variable>
23 #include <cstdint>
24 #include <mutex>
25 #include <vector>
26
27 #include "android-base/thread_annotations.h"
28
29 #include "chre/core/event_loop_manager.h"
30 #include "chre/core/nanoapp.h"
31 #include "chre/nanoapp.h"
32 #include "chre/util/unique_ptr.h"
33 #include "test_event.h"
34 #include "test_event_queue.h"
35
36 namespace chre {
37
38 //! Gets/Sets the timeout for wait/triggerWait() calls.
39 std::chrono::nanoseconds getWaitTimeout();
40 void setWaitTimeout(uint64_t timeout);
41
42 constexpr uint64_t kDefaultTestNanoappId = 0x0123456789abcdef;
43
44 /**
45 * Unregister all nanoapps.
46 *
47 * This is called by the test framework to unregister all nanoapps after each
48 * test. The destructor is called when the nanoapp is unregistered.
49 */
50 void unregisterAllTestNanoapps();
51
52 /**
53 * Information about a test nanoapp.
54 */
55 struct TestNanoappInfo {
56 const char *name = "Test";
57 uint64_t id = kDefaultTestNanoappId;
58 uint32_t version = 0;
59 uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE;
60 };
61
62 /**
63 * Test nanoapp.
64 *
65 * Tests typically inherit this class and override the entry points to test
66 * the nanoapp behavior.
67 *
68 * The bulk of the code should be in the handleEvent method to respond to
69 * events sent to the nanoapp by the platform and by the sendEventToNanoapp
70 * function. start and end can be use to setup and cleanup the test
71 * environment around each test.
72 *
73 * Note: end is only executed when the nanoapp is explicitly unloaded.
74 */
75 class TestNanoapp {
76 public:
77 TestNanoapp() = default;
TestNanoapp(TestNanoappInfo info)78 explicit TestNanoapp(TestNanoappInfo info) : mTestNanoappInfo(info) {}
~TestNanoapp()79 virtual ~TestNanoapp() {}
80
81 // NanoappStart Entrypoint.
start()82 virtual bool start() {
83 return true;
84 }
85
86 // nanoappHandleEvent Entrypoint.
handleEvent(uint32_t,uint16_t,const void *)87 virtual void handleEvent(uint32_t /*senderInstanceId*/,
88 uint16_t /*eventType*/, const void * /*eventData*/) {
89 }
90
91 // nanoappEnd Entrypoint.
end()92 virtual void end() {}
93
name()94 const char *name() {
95 return mTestNanoappInfo.name;
96 }
97
id()98 uint64_t id() {
99 return mTestNanoappInfo.id;
100 }
101
version()102 uint32_t version() {
103 return mTestNanoappInfo.version;
104 }
105
perms()106 uint32_t perms() {
107 return mTestNanoappInfo.perms;
108 }
109
110 //! Call this function to trigger the wait condition and release the
111 //! waiting thread. This should only be called by the nanoapp in handleEvent.
triggerWait(uint16_t eventType)112 void triggerWait(uint16_t eventType) {
113 mWaitingEventTypes.insert(eventType);
114 mCondVar.notify_one();
115 }
116
117 //! Completes action and expects it to return true, then waits for
118 //! triggerWait() to be called by the nanoapp with the given eventType.
doActionAndWait(const std::function<bool ()> & action,uint16_t eventType)119 void doActionAndWait(const std::function<bool()> &action,
120 uint16_t eventType) {
121 std::unique_lock<std::mutex> lock(mMutex);
122 EXPECT_TRUE(action());
123 mCondVar.wait_for(lock, getWaitTimeout(), [this, eventType]() {
124 return mWaitingEventTypes.find(eventType) != mWaitingEventTypes.end();
125 });
126 auto iter = mWaitingEventTypes.find(eventType);
127 ASSERT_NE(iter, mWaitingEventTypes.end());
128 mWaitingEventTypes.erase(iter);
129 }
130
131 //! Waits for triggerWait() to be called by the nanoapp with the given
132 //! eventType.
wait(uint16_t eventType)133 void wait(uint16_t eventType) {
134 doActionAndWait([]() { return true; }, eventType);
135 }
136
mutex()137 std::mutex &mutex() {
138 return mMutex;
139 }
140
141 private:
142 const TestNanoappInfo mTestNanoappInfo;
143
144 //! Mutex and condition variable used to wait for triggerWait() to be
145 //! called.
146 std::mutex mMutex;
147 std::condition_variable mCondVar;
148 std::set<uint16_t> mWaitingEventTypes GUARDED_BY(mMutex);
149 };
150
151 /**
152 * @return a pointer to a registered nanoapp or nullptr if the appId is not
153 * registered.
154 */
155 TestNanoapp *queryNanoapp(uint64_t appId);
156
157 /**
158 * @return the statically loaded nanoapp based on the arguments.
159 *
160 * @see chreNslNanoappInfo for param descriptions.
161 */
162 UniquePtr<Nanoapp> createStaticNanoapp(
163 const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms,
164 decltype(nanoappStart) *startFunc,
165 decltype(nanoappHandleEvent) *handleEventFunc,
166 decltype(nanoappEnd) *endFunc);
167
168 /**
169 * @return the statically loaded nanoapp based on the arguments, additionally
170 * sets info struct version
171 *
172 * @see chreNslNanoappInfo for param descriptions.
173 */
174 UniquePtr<Nanoapp> createStaticNanoapp(
175 uint8_t infoStructVersion, const char *name, uint64_t appId,
176 uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc,
177 decltype(nanoappHandleEvent) *handleEventFunc,
178 decltype(nanoappEnd) *endFunc);
179
180 /**
181 * Deletes memory allocated by createStaticNanoapp.
182 *
183 * This function must be called when the nanoapp is no more used.
184 */
185 void deleteNanoappInfos();
186
187 /**
188 * Default CHRE nanoapp entry points that don't do anything.
189 */
190 bool defaultNanoappStart();
191 void defaultNanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
192 const void *eventData);
193 void defaultNanoappEnd();
194
195 /**
196 * Create static nanoapp and load it in CHRE.
197 *
198 * This function returns after the nanoapp start has been executed.
199 *
200 * @see createStatic Nanoapp.
201 */
202 void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
203 uint32_t appPerms, decltype(nanoappStart) *startFunc,
204 decltype(nanoappHandleEvent) *handleEventFunc,
205 decltype(nanoappEnd) *endFunc);
206
207 /**
208 * Create a static nanoapp and load it in CHRE.
209 *
210 * This function returns after the nanoapp start has been executed.
211 *
212 * @return The id of the nanoapp.
213 */
214 uint64_t loadNanoapp(UniquePtr<TestNanoapp> app);
215
216 /**
217 * Unload nanoapp corresponding to appId.
218 *
219 * This function returns after the nanoapp end has been executed.
220 *
221 * @param appId App Id of nanoapp to be unloaded.
222 */
223 void unloadNanoapp(uint64_t appId);
224
225 /**
226 * A convenience deferred callback function that can be used to start an
227 * already loaded nanoapp.
228 *
229 * @param type The callback type.
230 * @param nanoapp A pointer to the nanoapp that is already loaded.
231 */
232 void testFinishLoadingNanoappCallback(SystemCallbackType type,
233 UniquePtr<Nanoapp> &&nanoapp);
234
235 /**
236 * A convenience deferred callback function to unload a nanoapp.
237 *
238 * @param type The callback type.
239 * @param data The data containing the appId.
240 * @param extraData Extra data.
241 */
242 void testFinishUnloadingNanoappCallback(uint16_t type, void *data,
243 void *extraData);
244
245 /**
246 * Deallocate the memory allocated for a TestEvent.
247 */
248 void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData);
249
250 /**
251 * Sends a message to a nanoapp.
252 *
253 * This function is typically used to execute code in the context of the
254 * nanoapp in its handleEvent method.
255 *
256 * @param appId ID of the nanoapp.
257 * @param eventType The event to send.
258 */
259 void sendEventToNanoapp(uint64_t appId, uint16_t eventType);
260
261 /**
262 * Sends a message to a nanoapp and waits for the nanoapp code to call
263 * triggerWait(). The nanoapp code must call triggerWait() to release the
264 * waiting thread or this function will never return.
265 *
266 * This function is typically used to execute code in the context of the
267 * nanoapp in its handleEvent method.
268 *
269 * @param appId ID of the nanoapp.
270 * @param eventType The event to send.
271 * @param waitEventType The event to wait for.
272 */
273 void sendEventToNanoappAndWait(uint64_t appId, uint16_t eventType,
274 uint16_t waitEventType);
275
276 /**
277 * Sends a message to a nanoapp with data.
278 *
279 * This function is typically used to execute code in the context of the
280 * nanoapp in its handleEvent method.
281 *
282 * The nanoapp handleEvent function will receive a a TestEvent instance
283 * populated with the eventType and a pointer to as copy of the evenData as
284 * a CHRE_EVENT_TEST_EVENT event.
285 *
286 * @param appId ID of the nanoapp.
287 * @param eventType The event to send.
288 * @param eventData The data to send.
289 */
290 template <typename T>
sendEventToNanoapp(uint64_t appId,uint16_t eventType,const T & eventData)291 void sendEventToNanoapp(uint64_t appId, uint16_t eventType,
292 const T &eventData) {
293 static_assert(std::is_trivial<T>::value);
294 uint16_t instanceId;
295 if (EventLoopManagerSingleton::get()
296 ->getEventLoop()
297 .findNanoappInstanceIdByAppId(appId, &instanceId)) {
298 auto event = memoryAlloc<TestEvent>();
299 ASSERT_NE(event, nullptr);
300 event->type = eventType;
301 auto ptr = memoryAlloc<T>();
302 ASSERT_NE(ptr, nullptr);
303 *ptr = eventData;
304 event->data = ptr;
305 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
306 CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
307 freeTestEventDataCallback, instanceId);
308 } else {
309 LOGE("No instance found for nanoapp id = 0x%016" PRIx64, appId);
310 }
311 }
312
313 /**
314 * Sends a message to a nanoapp with data and waits for the nanoapp code to call
315 * triggerWait(). The nanoapp code must call triggerWait() to release the
316 * waiting thread or this function will never return.
317 *
318 * This function is typically used to execute code in the context of the
319 * nanoapp in its handleEvent method.
320 *
321 * The nanoapp handleEvent function will receive a a TestEvent instance
322 * populated with the eventType and a pointer to as copy of the evenData as
323 * a CHRE_EVENT_TEST_EVENT event.
324 *
325 * @param appId ID of the nanoapp.
326 * @param eventType The event to send.
327 * @param eventData The data to send.
328 * @param waitEventType The event to wait for.
329 */
330 template <typename T>
sendEventToNanoappAndWait(uint64_t appId,uint16_t eventType,const T & eventData,uint16_t waitEventType)331 void sendEventToNanoappAndWait(uint64_t appId, uint16_t eventType,
332 const T &eventData, uint16_t waitEventType) {
333 TestNanoapp *app = queryNanoapp(appId);
334 ASSERT_NE(app, nullptr);
335 app->doActionAndWait(
336 [appId, eventType, &eventData]() {
337 sendEventToNanoapp(appId, eventType, eventData);
338 return true;
339 },
340 waitEventType);
341 }
342
343 } // namespace chre
344
345 #endif // CHRE_SIMULATION_TEST_UTIL_H_
346