• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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