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 <chre/nanoapp.h>
21 #include <cstdint>
22
23 #include "chre/core/event_loop_manager.h"
24 #include "chre/core/nanoapp.h"
25 #include "chre/util/unique_ptr.h"
26 #include "test_event.h"
27 #include "test_event_queue.h"
28
29 namespace chre {
30
31 struct TestNanoapp;
32
33 /**
34 * @return the statically loaded nanoapp based on the arguments.
35 *
36 * @see chreNslNanoappInfo for param descriptions.
37 */
38 UniquePtr<Nanoapp> createStaticNanoapp(
39 const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms,
40 decltype(nanoappStart) *startFunc,
41 decltype(nanoappHandleEvent) *handleEventFunc,
42 decltype(nanoappEnd) *endFunc);
43
44 /**
45 * @return the statically loaded nanoapp based on the arguments, additionally
46 * sets info struct version
47 *
48 * @see chreNslNanoappInfo for param descriptions.
49 */
50 UniquePtr<Nanoapp> createStaticNanoapp(
51 uint8_t infoStructVersion, const char *name, uint64_t appId,
52 uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc,
53 decltype(nanoappHandleEvent) *handleEventFunc,
54 decltype(nanoappEnd) *endFunc);
55
56 /**
57 * Deletes memory allocated by createStaticNanoapp.
58 *
59 * This function must be called when the nanoapp is no more used.
60 */
61 void deleteNanoappInfos();
62
63 /**
64 * Default CHRE nanoapp entry points that don't do anything.
65 */
66 bool defaultNanoappStart();
67 void defaultNanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
68 const void *eventData);
69 void defaultNanoappEnd();
70
71 /**
72 * Create static nanoapp and load it in CHRE.
73 *
74 * This function returns after the nanoapp start has been executed.
75 *
76 * @see createStatic Nanoapp.
77 */
78 void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
79 uint32_t appPerms, decltype(nanoappStart) *startFunc,
80 decltype(nanoappHandleEvent) *handleEventFunc,
81 decltype(nanoappEnd) *endFunc);
82
83 /**
84 * Create a static nanoapp and load it in CHRE.
85 *
86 * This function returns after the nanoapp start has been executed.
87 *
88 * @return An instance of the TestNanoapp.
89 */
90 template <class Nanoapp>
loadNanoapp()91 Nanoapp loadNanoapp() {
92 static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
93 Nanoapp app;
94 loadNanoapp(app.name, app.id, app.version, app.perms, app.start,
95 app.handleEvent, app.end);
96
97 return app;
98 }
99
100 /**
101 * Unload a test nanoapp.
102 *
103 * This function returns after the nanoapp end has been executed.
104 *
105 * @param app An instance of TestNanoapp.
106 */
107 template <class Nanoapp>
unloadNanoapp(Nanoapp app)108 void unloadNanoapp(Nanoapp app) {
109 static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
110 unloadNanoapp(app.id);
111 }
112
113 /**
114 * Unload nanoapp corresponding to appId.
115 *
116 * This function returns after the nanoapp end has been executed.
117 *
118 * @param appId App Id of nanoapp to be unloaded.
119 */
120 template <>
121 void unloadNanoapp<uint64_t>(uint64_t appId);
122
123 /**
124 * A convenience deferred callback function that can be used to start an already
125 * loaded nanoapp.
126 *
127 * @param type The callback type.
128 * @param nanoapp A pointer to the nanoapp that is already loaded.
129 */
130 void testFinishLoadingNanoappCallback(SystemCallbackType type,
131 UniquePtr<Nanoapp> &&nanoapp);
132
133 /**
134 * A convenience deferred callback function to unload a nanoapp.
135 *
136 * @param type The callback type.
137 * @param data The data containing the appId.
138 * @param extraData Extra data.
139 */
140 void testFinishUnloadingNanoappCallback(uint16_t type, void *data,
141 void *extraData);
142
143 /**
144 * Test nanoapp.
145 *
146 * Tests typically inherit this struct to test the nanoapp behavior.
147 * The bulk of the code should be in the handleEvent closure to respond to
148 * events sent to the nanoapp by the platform and by the sendEventToNanoapp
149 * function. start and end can be use to setup and cleanup the test environment
150 * around each test.
151 *
152 * Note: end is only executed when the nanoapp is explicitly unloaded.
153 */
154 struct TestNanoapp {
155 const char *name = "Test";
156 uint64_t id = 0x0123456789abcdef;
157 uint32_t version = 0;
158 uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE;
159
decltypeTestNanoapp160 decltype(nanoappStart) *start = []() { return true; };
161
decltypeTestNanoapp162 decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t,
163 const void *) {};
164
decltypeTestNanoapp165 decltype(nanoappEnd) *end = []() {};
166 };
167
168 /**
169 * Deallocate the memory allocated for a TestEvent.
170 */
171 void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData);
172
173 /**
174 * Sends a message to a nanoapp.
175 *
176 * This function is typically used to execute code in the context of the
177 * nanoapp in its handleEvent method.
178 *
179 * @param app An instance of TestNanoapp.
180 * @param eventType The event to send.
181 */
182 template <class Nanoapp>
sendEventToNanoapp(const Nanoapp & app,uint16_t eventType)183 void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType) {
184 static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
185 uint16_t instanceId;
186 if (EventLoopManagerSingleton::get()
187 ->getEventLoop()
188 .findNanoappInstanceIdByAppId(app.id, &instanceId)) {
189 auto event = memoryAlloc<TestEvent>();
190 ASSERT_NE(event, nullptr);
191 event->type = eventType;
192 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
193 CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
194 freeTestEventDataCallback, instanceId);
195
196 } else {
197 LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id);
198 }
199 }
200
201 /**
202 * Sends a message to a nanoapp with data.
203 *
204 * This function is typically used to execute code in the context of the
205 * nanoapp in its handleEvent method.
206 *
207 * The nanoapp handleEvent function will receive a a TestEvent instance
208 * populated with the eventType and a pointer to as copy of the evenData as
209 * a CHRE_EVENT_TEST_EVENT event.
210 *
211 * @param app An instance of TestNanoapp.
212 * @param eventType The event to send.
213 * @param eventData The data to send.
214 */
215 template <class Nanoapp, class T>
sendEventToNanoapp(const Nanoapp & app,uint16_t eventType,const T & eventData)216 void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType,
217 const T &eventData) {
218 static_assert(std::is_base_of<TestNanoapp, Nanoapp>::value);
219 static_assert(std::is_trivial<T>::value);
220 uint16_t instanceId;
221 if (EventLoopManagerSingleton::get()
222 ->getEventLoop()
223 .findNanoappInstanceIdByAppId(app.id, &instanceId)) {
224 auto event = memoryAlloc<TestEvent>();
225 ASSERT_NE(event, nullptr);
226 event->type = eventType;
227 auto ptr = memoryAlloc<T>();
228 ASSERT_NE(ptr, nullptr);
229 *ptr = eventData;
230 event->data = ptr;
231 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
232 CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
233 freeTestEventDataCallback, instanceId);
234 } else {
235 LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id);
236 }
237 }
238
239 } // namespace chre
240
241 #endif // CHRE_SIMULATION_TEST_UTIL_H_
242