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 #ifndef CHRE_SIMULATION_TEST_UTIL_H_
18 #define CHRE_SIMULATION_TEST_UTIL_H_
19 
20 #include <chre/nanoapp.h>
21 #include <cstdint>
22 
23 #include "chre/core/event_loop_manager.h"
24 #include "chre/core/nanoapp.h"
25 #include "chre/util/unique_ptr.h"
26 #include "test_event.h"
27 #include "test_event_queue.h"
28 
29 namespace chre {
30 
31 constexpr uint64_t kDefaultTestNanoappId = 0x0123456789abcdef;
32 
33 /**
34  * Unregister all nanoapps.
35  *
36  * This is called by the test framework to unregister all nanoapps after each
37  * test. The destructor is called when the nanoapp is unregistered.
38  */
39 void unregisterAllTestNanoapps();
40 
41 /**
42  * Information about a test nanoapp.
43  */
44 struct TestNanoappInfo {
45   const char *name = "Test";
46   uint64_t id = kDefaultTestNanoappId;
47   uint32_t version = 0;
48   uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE;
49 };
50 
51 /**
52  * Test nanoapp.
53  *
54  * Tests typically inherit this class and override the entry points to test the
55  * nanoapp behavior.
56  *
57  * The bulk of the code should be in the handleEvent method to respond to
58  * events sent to the nanoapp by the platform and by the sendEventToNanoapp
59  * function. start and end can be use to setup and cleanup the test environment
60  * around each test.
61  *
62  * Note: end is only executed when the nanoapp is explicitly unloaded.
63  */
64 class TestNanoapp {
65  public:
66   TestNanoapp() = default;
TestNanoapp(TestNanoappInfo info)67   explicit TestNanoapp(TestNanoappInfo info) : mTestNanoappInfo(info) {}
~TestNanoapp()68   virtual ~TestNanoapp() {}
69 
70   // NanoappStart Entrypoint.
start()71   virtual bool start() {
72     return true;
73   }
74 
75   // nanoappHandleEvent Entrypoint.
handleEvent(uint32_t,uint16_t,const void *)76   virtual void handleEvent(uint32_t /*senderInstanceId*/,
77                            uint16_t /*eventType*/, const void * /*eventData*/) {
78   }
79 
80   // nanoappEnd Entrypoint.
end()81   virtual void end() {}
82 
name()83   const char *name() {
84     return mTestNanoappInfo.name;
85   }
86 
id()87   uint64_t id() {
88     return mTestNanoappInfo.id;
89   }
90 
version()91   uint32_t version() {
92     return mTestNanoappInfo.version;
93   }
94 
perms()95   uint32_t perms() {
96     return mTestNanoappInfo.perms;
97   }
98 
99  private:
100   const TestNanoappInfo mTestNanoappInfo;
101 };
102 
103 /**
104  * @return the statically loaded nanoapp based on the arguments.
105  *
106  * @see chreNslNanoappInfo for param descriptions.
107  */
108 UniquePtr<Nanoapp> createStaticNanoapp(
109     const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms,
110     decltype(nanoappStart) *startFunc,
111     decltype(nanoappHandleEvent) *handleEventFunc,
112     decltype(nanoappEnd) *endFunc);
113 
114 /**
115  * @return the statically loaded nanoapp based on the arguments, additionally
116  * sets info struct version
117  *
118  * @see chreNslNanoappInfo for param descriptions.
119  */
120 UniquePtr<Nanoapp> createStaticNanoapp(
121     uint8_t infoStructVersion, const char *name, uint64_t appId,
122     uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc,
123     decltype(nanoappHandleEvent) *handleEventFunc,
124     decltype(nanoappEnd) *endFunc);
125 
126 /**
127  * Deletes memory allocated by createStaticNanoapp.
128  *
129  * This function must be called when the nanoapp is no more used.
130  */
131 void deleteNanoappInfos();
132 
133 /**
134  * Default CHRE nanoapp entry points that don't do anything.
135  */
136 bool defaultNanoappStart();
137 void defaultNanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType,
138                                const void *eventData);
139 void defaultNanoappEnd();
140 
141 /**
142  * Create static nanoapp and load it in CHRE.
143  *
144  * This function returns after the nanoapp start has been executed.
145  *
146  * @see createStatic Nanoapp.
147  */
148 void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion,
149                  uint32_t appPerms, decltype(nanoappStart) *startFunc,
150                  decltype(nanoappHandleEvent) *handleEventFunc,
151                  decltype(nanoappEnd) *endFunc);
152 
153 /**
154  * Create a static nanoapp and load it in CHRE.
155  *
156  * This function returns after the nanoapp start has been executed.
157  *
158  * @return The id of the nanoapp.
159  */
160 uint64_t loadNanoapp(UniquePtr<TestNanoapp> app);
161 
162 /**
163  * Unload nanoapp corresponding to appId.
164  *
165  * This function returns after the nanoapp end has been executed.
166  *
167  * @param appId App Id of nanoapp to be unloaded.
168  */
169 void unloadNanoapp(uint64_t appId);
170 
171 /**
172  * A convenience deferred callback function that can be used to start an already
173  * loaded nanoapp.
174  *
175  * @param type The callback type.
176  * @param nanoapp A pointer to the nanoapp that is already loaded.
177  */
178 void testFinishLoadingNanoappCallback(SystemCallbackType type,
179                                       UniquePtr<Nanoapp> &&nanoapp);
180 
181 /**
182  * A convenience deferred callback function to unload a nanoapp.
183  *
184  * @param type The callback type.
185  * @param data The data containing the appId.
186  * @param extraData Extra data.
187  */
188 void testFinishUnloadingNanoappCallback(uint16_t type, void *data,
189                                         void *extraData);
190 
191 /**
192  * Deallocate the memory allocated for a TestEvent.
193  */
194 void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData);
195 
196 /**
197  * Sends a message to a nanoapp.
198  *
199  * This function is typically used to execute code in the context of the
200  * nanoapp in its handleEvent method.
201  *
202  * @param appId ID of the nanoapp.
203  * @param eventType The event to send.
204  */
205 void sendEventToNanoapp(uint64_t appId, uint16_t eventType);
206 
207 /**
208  * Sends a message to a nanoapp with data.
209  *
210  * This function is typically used to execute code in the context of the
211  * nanoapp in its handleEvent method.
212  *
213  * The nanoapp handleEvent function will receive a a TestEvent instance
214  * populated with the eventType and a pointer to as copy of the evenData as
215  * a CHRE_EVENT_TEST_EVENT event.
216  *
217  * @param appId ID of the nanoapp.
218  * @param eventType The event to send.
219  * @param eventData The data to send.
220  */
221 template <class T>
sendEventToNanoapp(uint64_t appId,uint16_t eventType,const T & eventData)222 void sendEventToNanoapp(uint64_t appId, uint16_t eventType,
223                         const T &eventData) {
224   static_assert(std::is_trivial<T>::value);
225   uint16_t instanceId;
226   if (EventLoopManagerSingleton::get()
227           ->getEventLoop()
228           .findNanoappInstanceIdByAppId(appId, &instanceId)) {
229     auto event = memoryAlloc<TestEvent>();
230     ASSERT_NE(event, nullptr);
231     event->type = eventType;
232     auto ptr = memoryAlloc<T>();
233     ASSERT_NE(ptr, nullptr);
234     *ptr = eventData;
235     event->data = ptr;
236     EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
237         CHRE_EVENT_TEST_EVENT, static_cast<void *>(event),
238         freeTestEventDataCallback, instanceId);
239   } else {
240     LOGE("No instance found for nanoapp id = 0x%016" PRIx64, appId);
241   }
242 }
243 
244 }  // namespace chre
245 
246 #endif  // CHRE_SIMULATION_TEST_UTIL_H_
247