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 #include "test_util.h"
18
19 #include <gtest/gtest.h>
20 #include <cstdint>
21 #include <unordered_map>
22
23 #include "chre/core/event_loop_manager.h"
24 #include "chre/core/nanoapp.h"
25 #include "chre/platform/system_time.h"
26 #include "chre/util/dynamic_vector.h"
27 #include "chre/util/macros.h"
28 #include "chre/util/memory.h"
29 #include "chre_api/chre/version.h"
30 #include "nanoapp/include/chre_nsl_internal/platform/shared/nanoapp_support_lib_dso.h"
31
32 namespace chre {
33
34 namespace {
35 /**
36 * List of chreNslNanoappInfo.
37 *
38 * Keep the chreNslNanoappInfo instances alive for the lifetime of the test
39 * nanoapps.
40 */
41 DynamicVector<UniquePtr<chreNslNanoappInfo>> gNanoappInfos;
42
43 /** Registry of nanoapp by ID. */
44 std::unordered_map<uint64_t, UniquePtr<TestNanoapp>> nanoapps;
45
46 //! The timeout for wait/triggerWait() calls.
47 uint64_t gWaitTimeout = 3 * kOneSecondInNanoseconds;
48
49 /**
50 * Nanoapp start.
51 *
52 * Invokes the start method of a registered TestNanoapp.
53 */
start()54 bool start() {
55 uint64_t id = chreGetAppId();
56 TestNanoapp *app = queryNanoapp(id);
57 if (app == nullptr) {
58 LOGE("[start] unregistered nanoapp 0x%016" PRIx64, id);
59 return false;
60 }
61 return app->start();
62 }
63
64 /**
65 * Nanoapp handleEvent.
66 *
67 * Invokes the handleMethod method of a registered TestNanoapp.
68 */
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)69 void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
70 const void *eventData) {
71 uint64_t id = chreGetAppId();
72 TestNanoapp *app = queryNanoapp(id);
73 if (app == nullptr) {
74 LOGE("[handleEvent] unregistered nanoapp 0x%016" PRIx64, id);
75 } else {
76 std::lock_guard<std::mutex> lock(app->mutex());
77 app->handleEvent(senderInstanceId, eventType, eventData);
78 }
79 }
80
81 /**
82 * Nanoapp end.
83 *
84 * Invokes the end method of a registered TestNanoapp.
85 */
end()86 void end() {
87 uint64_t id = chreGetAppId();
88 TestNanoapp *app = queryNanoapp(id);
89 if (app == nullptr) {
90 LOGE("[end] unregistered nanoapp 0x%016" PRIx64, id);
91 } else {
92 app->end();
93 }
94 }
95
96 /**
97 * Registers a test nanoapp.
98 *
99 * TestNanoapps are registered when they are loaded so that their entry point
100 * methods can be called.
101 */
registerNanoapp(UniquePtr<TestNanoapp> app)102 void registerNanoapp(UniquePtr<TestNanoapp> app) {
103 if (nanoapps.count(app->id()) != 0) {
104 LOGE("A nanoapp with the same id is already registered");
105 } else {
106 nanoapps[app->id()] = std::move(app);
107 }
108 }
109
110 /**
111 * Unregisters a nanoapp.
112 *
113 * Calls the TestNanoapp destructor.
114 */
unregisterNanoapp(uint64_t appId)115 void unregisterNanoapp(uint64_t appId) {
116 if (nanoapps.erase(appId) == 0) {
117 LOGE("The nanoapp is not registered");
118 }
119 }
120
121 } // namespace
122
getWaitTimeout()123 std::chrono::nanoseconds getWaitTimeout() {
124 return std::chrono::nanoseconds(gWaitTimeout);
125 }
126
setWaitTimeout(uint64_t timeout)127 void setWaitTimeout(uint64_t timeout) {
128 gWaitTimeout = timeout;
129 }
130
queryNanoapp(uint64_t appId)131 TestNanoapp *queryNanoapp(uint64_t appId) {
132 return nanoapps.count(appId) == 0 ? nullptr : nanoapps[appId].get();
133 }
134
unregisterAllTestNanoapps()135 void unregisterAllTestNanoapps() {
136 nanoapps.clear();
137 }
138
createStaticNanoapp(const char * name,uint64_t appId,uint32_t appVersion,uint32_t appPerms,decltype(nanoappStart) * startFunc,decltype(nanoappHandleEvent) * handleEventFunc,decltype(nanoappEnd) * endFunc)139 UniquePtr<Nanoapp> createStaticNanoapp(
140 const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms,
141 decltype(nanoappStart) *startFunc,
142 decltype(nanoappHandleEvent) *handleEventFunc,
143 decltype(nanoappEnd) *endFunc) {
144 return createStaticNanoapp(CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION, name,
145 appId, appVersion, appPerms, startFunc,
146 handleEventFunc, endFunc);
147 }
148
createStaticNanoapp(uint8_t infoStructVersion,const char * name,uint64_t appId,uint32_t appVersion,uint32_t appPerms,decltype(nanoappStart) * startFunc,decltype(nanoappHandleEvent) * handleEventFunc,decltype(nanoappEnd) * endFunc)149 UniquePtr<Nanoapp> createStaticNanoapp(
150 uint8_t infoStructVersion, const char *name, uint64_t appId,
151 uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc,
152 decltype(nanoappHandleEvent) *handleEventFunc,
153 decltype(nanoappEnd) *endFunc) {
154 auto nanoapp = MakeUnique<Nanoapp>();
155 auto nanoappInfo = MakeUnique<chreNslNanoappInfo>();
156 chreNslNanoappInfo *appInfo = nanoappInfo.get();
157 gNanoappInfos.push_back(std::move(nanoappInfo));
158 appInfo->magic = CHRE_NSL_NANOAPP_INFO_MAGIC;
159 appInfo->structMinorVersion = infoStructVersion;
160 appInfo->targetApiVersion = CHRE_API_VERSION;
161 appInfo->vendor = "Google";
162 appInfo->name = name;
163 appInfo->isSystemNanoapp = true;
164 appInfo->isTcmNanoapp = true;
165 appInfo->appId = appId;
166 appInfo->appVersion = appVersion;
167 appInfo->entryPoints.start = startFunc;
168 appInfo->entryPoints.handleEvent = handleEventFunc;
169 appInfo->entryPoints.end = endFunc;
170 appInfo->appVersionString = "<undefined>";
171 appInfo->appPermissions = appPerms;
172 EXPECT_FALSE(nanoapp.isNull());
173 nanoapp->loadStatic(appInfo);
174
175 return nanoapp;
176 }
177
deleteNanoappInfos()178 void deleteNanoappInfos() {
179 gNanoappInfos.clear();
180 }
181
defaultNanoappStart()182 bool defaultNanoappStart() {
183 return true;
184 }
185
defaultNanoappHandleEvent(uint32_t,uint16_t,const void *)186 void defaultNanoappHandleEvent(uint32_t /*senderInstanceId*/,
187 uint16_t /*eventType*/,
188 const void * /*eventData*/) {}
189
defaultNanoappEnd()190 void defaultNanoappEnd() {}
191
loadNanoapp(const char * name,uint64_t appId,uint32_t appVersion,uint32_t appPerms,decltype(nanoappStart) * startFunc,decltype(nanoappHandleEvent) * handleEventFunc,decltype(nanoappEnd) * endFunc)192 void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
193 uint32_t appPerms, decltype(nanoappStart) *startFunc,
194 decltype(nanoappHandleEvent) *handleEventFunc,
195 decltype(nanoappEnd) *endFunc) {
196 UniquePtr<Nanoapp> nanoapp = createStaticNanoapp(
197 name, appId, appVersion, appPerms, startFunc, handleEventFunc, endFunc);
198
199 EventLoopManagerSingleton::get()->deferCallback(
200 SystemCallbackType::FinishLoadingNanoapp, std::move(nanoapp),
201 testFinishLoadingNanoappCallback);
202
203 TestEventQueueSingleton::get()->waitForEvent(
204 CHRE_EVENT_SIMULATION_TEST_NANOAPP_LOADED);
205 }
206
loadNanoapp(UniquePtr<TestNanoapp> app)207 uint64_t loadNanoapp(UniquePtr<TestNanoapp> app) {
208 TestNanoapp *pApp = app.get();
209 registerNanoapp(std::move(app));
210 loadNanoapp(pApp->name(), pApp->id(), pApp->version(), pApp->perms(), &start,
211 &handleEvent, &end);
212
213 return pApp->id();
214 }
215
sendEventToNanoapp(uint64_t appId,uint16_t eventType)216 void sendEventToNanoapp(uint64_t appId, uint16_t eventType) {
217 uint16_t instanceId;
218 if (EventLoopManagerSingleton::get()
219 ->getEventLoop()
220 .findNanoappInstanceIdByAppId(appId, &instanceId)) {
221 auto event = memoryAlloc<TestEvent>();
222 ASSERT_NE(event, nullptr);
223 event->type = eventType;
224 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
225 CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
226 freeTestEventDataCallback, instanceId);
227
228 } else {
229 LOGE("No instance found for nanoapp id = 0x%016" PRIx64, appId);
230 }
231 }
232
sendEventToNanoappAndWait(uint64_t appId,uint16_t eventType,uint16_t waitEventType)233 void sendEventToNanoappAndWait(uint64_t appId, uint16_t eventType,
234 uint16_t waitEventType) {
235 TestNanoapp *app = queryNanoapp(appId);
236 ASSERT_NE(app, nullptr);
237 app->doActionAndWait(
238 [appId, eventType]() {
239 sendEventToNanoapp(appId, eventType);
240 return true;
241 },
242 waitEventType);
243 }
244
unloadNanoapp(uint64_t appId)245 void unloadNanoapp(uint64_t appId) {
246 uint64_t *ptr = memoryAlloc<uint64_t>();
247 ASSERT_NE(ptr, nullptr);
248 *ptr = appId;
249 EventLoopManagerSingleton::get()->deferCallback(
250 SystemCallbackType::HandleUnloadNanoapp, ptr,
251 testFinishUnloadingNanoappCallback);
252
253 TestEventQueueSingleton::get()->waitForEvent(
254 CHRE_EVENT_SIMULATION_TEST_NANOAPP_UNLOADED);
255
256 unregisterNanoapp(appId);
257 }
258
testFinishLoadingNanoappCallback(SystemCallbackType,UniquePtr<Nanoapp> && nanoapp)259 void testFinishLoadingNanoappCallback(SystemCallbackType /* type */,
260 UniquePtr<Nanoapp> &&nanoapp) {
261 EventLoopManagerSingleton::get()->getEventLoop().startNanoapp(nanoapp);
262 TestEventQueueSingleton::get()->pushEvent(
263 CHRE_EVENT_SIMULATION_TEST_NANOAPP_LOADED);
264 }
265
testFinishUnloadingNanoappCallback(uint16_t,void * data,void *)266 void testFinishUnloadingNanoappCallback(uint16_t /* type */, void *data,
267 void * /* extraData */) {
268 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
269 uint16_t instanceId = 0;
270 uint64_t *appId = static_cast<uint64_t *>(data);
271 eventLoop.findNanoappInstanceIdByAppId(*appId, &instanceId);
272 eventLoop.unloadNanoapp(instanceId, true);
273 memoryFree(data);
274 TestEventQueueSingleton::get()->pushEvent(
275 CHRE_EVENT_SIMULATION_TEST_NANOAPP_UNLOADED);
276 }
277
freeTestEventDataCallback(uint16_t,void * eventData)278 void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData) {
279 auto testEvent = static_cast<TestEvent *>(eventData);
280 memoryFree(testEvent->data);
281 memoryFree(testEvent);
282 }
283
284 } // namespace chre
285