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