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