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