• 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 <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