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