• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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