1 /*
2 * Copyright (C) 2016 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 /**
18 * Nanoapp which performs a number of operations within nanoappStart().
19 *
20 * This nanoapp is to confirm a number of CHRE methods can be invoked from
21 * within nanoappStart(). There are other tests which test each of these
22 * CHRE methods more in depth. We're just doing a sanity check that calling
23 * from nanoappStart() works at all.
24 *
25 * Specifically, we're testing:
26 * o chreHeapAlloc() and chreHeapFree()
27 * o chreGetInstanceId()
28 * o chreSendEvent() [*]
29 * o chreTimerSet() [*]
30 * o chreSensorFindDefault() and chreSensorConfigure() [*]
31 * o chreSendMessageToHost() [**]
32 *
33 * [*] These require nanoappHandleEvent() to be called successfully in order
34 * to confirm.
35 * [**] This is confirmed by the host receiving this message.
36 *
37 * This isn't a "general" test, so it doesn't have a standard communication
38 * protocol. Notably, the Host doesn't send any messages to this nanoapp.
39 *
40 * Protocol:
41 * Nanoapp to Host: kContinue
42 * Nanoapp to Host: kSuccess
43 */
44
45 #include <cinttypes>
46
47 #include <chre.h>
48
49 #include <shared/send_message.h>
50 #include <shared/time_util.h>
51 #include <shared/test_success_marker.h>
52
53 using nanoapp_testing::MessageType;
54 using nanoapp_testing::TestSuccessMarker;
55 using nanoapp_testing::sendMessageToHost;
56 using nanoapp_testing::sendFatalFailureToHost;
57 using nanoapp_testing::sendFatalFailureToHostUint8;
58 using nanoapp_testing::sendSuccessToHost;
59
60 static bool gInMethod = false;
61 static uint32_t gInstanceId;
62 static uint32_t gTimerId;
63 static uint32_t gSensorHandle;
64
65 /**
66 * Busy startup stages and total number of stages.
67 */
68 enum BusyStartupStage {
69 BUSY_STARTUP_STAGE_SELF_EVENT = 0,
70 BUSY_STARTUP_STAGE_TIMER,
71 BUSY_STARTUP_STAGE_SENSOR,
72 BUSY_STARTUP_STAGE_COUNT,
73 };
74
75 //! TestSuccessMarker object to mark success of a stage.
76 TestSuccessMarker gTestSuccessMarker =
77 TestSuccessMarker(BUSY_STARTUP_STAGE_COUNT);
78
79 constexpr uint16_t kEventType = CHRE_EVENT_FIRST_USER_VALUE;
80
checkSelfEvent(uint16_t eventType,const uint32_t * eventData)81 static void checkSelfEvent(uint16_t eventType, const uint32_t *eventData) {
82 if (eventType != kEventType) {
83 uint32_t e = eventType;
84 sendFatalFailureToHost("Event from self, bad event type:", &e);
85 }
86 if (eventData == nullptr) {
87 sendFatalFailureToHost("Event from self, null data");
88 }
89 if (*eventData != gInstanceId) {
90 sendFatalFailureToHost("Event from self, bad data:", eventData);
91 }
92 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_SELF_EVENT);
93 }
94
checkTimerEvent(const uint32_t * eventData)95 static void checkTimerEvent(const uint32_t *eventData) {
96 if (eventData == nullptr) {
97 sendFatalFailureToHost("TimerEvent, null data");
98 }
99 if (*eventData != gInstanceId) {
100 sendFatalFailureToHost("TimerEvent, bad data:", eventData);
101 }
102 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_TIMER);
103 }
104
checkSensorEvent(const void * eventData)105 static void checkSensorEvent(const void *eventData) {
106 const chreSensorDataHeader* header =
107 static_cast<const chreSensorDataHeader *>(eventData);
108 if (header == nullptr) {
109 sendFatalFailureToHost("sensorEvent, null data");
110 }
111 if (header->sensorHandle != gSensorHandle) {
112 sendFatalFailureToHost("sensorEvent for wrong handle",
113 &header->sensorHandle);
114 }
115 if (header->readingCount == 0) {
116 sendFatalFailureToHost("sensorEvent has readingCount of 0");
117 }
118 if (header->reserved != 0) {
119 sendFatalFailureToHost("sensorEvent has non-zero reserved field");
120 }
121
122 if (chreGetApiVersion() < CHRE_API_VERSION_1_3) {
123 if (header->accuracy != 0) {
124 sendFatalFailureToHost("sensorEvent has non-zero reserved field");
125 }
126 } else if (header->accuracy > CHRE_SENSOR_ACCURACY_HIGH) {
127 sendFatalFailureToHostUint8("Sensor accuracy is not within valid range: ",
128 header->accuracy);
129 }
130
131 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_SENSOR);
132 }
133
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)134 extern "C" void nanoappHandleEvent(uint32_t senderInstanceId,
135 uint16_t eventType,
136 const void* eventData) {
137 if (gInMethod) {
138 sendFatalFailureToHost("CHRE reentered nanoapp");
139 }
140 gInMethod = true;
141 const uint32_t *intData = static_cast<const uint32_t *>(eventData);
142 if (senderInstanceId == gInstanceId) {
143 checkSelfEvent(eventType, intData);
144
145 } else if (senderInstanceId == CHRE_INSTANCE_ID) {
146 if (eventType == CHRE_EVENT_TIMER) {
147 checkTimerEvent(intData);
148 } else if (eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_DATA) {
149 checkSensorEvent(eventData);
150 } else if (eventType == CHRE_EVENT_SENSOR_SAMPLING_CHANGE) {
151 // This could have been generated when we configured the
152 // sensor. We just ignore it.
153 } else {
154 uint32_t e = eventType;
155 sendFatalFailureToHost("Unexpected event from CHRE:", &e);
156 }
157 } else {
158 sendFatalFailureToHost("Unexpected senderInstanceId",
159 &senderInstanceId);
160 }
161 gInMethod = false;
162 }
163
nanoappStart(void)164 extern "C" bool nanoappStart(void) {
165 gInMethod = true;
166 void *ptr = chreHeapAlloc(15);
167 if (ptr == nullptr) {
168 // TODO(b/32326854): We're not able to send messages from
169 // nanoappStart(), so we just use chreLog() here, and make
170 // the user look through the logs to determine why this failed.
171 chreLog(CHRE_LOG_ERROR, "Unable to malloc in start");
172 return false;
173 }
174 gInstanceId = chreGetInstanceId();
175 if (gInstanceId == CHRE_INSTANCE_ID) {
176 chreLog(CHRE_LOG_ERROR, "Got bad instance ID in start");
177 return false;
178 }
179
180 // Send an event to ourself.
181 if (!chreSendEvent(kEventType, &gInstanceId, nullptr, gInstanceId)) {
182 chreLog(CHRE_LOG_ERROR, "Failed chreSendEvent in start");
183 return false;
184 }
185
186 // One shot timer that should trigger very quickly.
187 gTimerId = chreTimerSet(1, &gInstanceId, true);
188 if (gTimerId == CHRE_TIMER_INVALID) {
189 chreLog(CHRE_LOG_ERROR, "Failed chreTimerSet in start");
190 return false;
191 }
192
193 // We don't have a way to confirm the 'free' worked, we'll just look
194 // to see that we didn't crash. We intentionally move this 'free' to
195 // be not immediately after the 'alloc', and still before we're done
196 // calling other methods.
197 chreHeapFree(ptr);
198
199 // Confirm we can find and configure a sensor.
200 if (!chreSensorFindDefault(CHRE_SENSOR_TYPE_ACCELEROMETER,
201 &gSensorHandle)) {
202 chreLog(CHRE_LOG_ERROR, "Failed sensorFindDefault in start");
203 return false;
204 }
205
206 // Configure accel request at 50 Hz (reasonable rate, e.g. for AR)
207 // TODO: Add a way to find the range of possible sample rates
208 if (!chreSensorConfigure(gSensorHandle,
209 CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS,
210 20 * nanoapp_testing::kOneMillisecondInNanoseconds,
211 CHRE_SENSOR_LATENCY_ASAP)) {
212 chreLog(CHRE_LOG_ERROR, "Failed sensorConfigure in start");
213 return false;
214 }
215
216 // TODO(b/32326854): Confirm we can send a message to the host.
217
218 gInMethod = false;
219 return true;
220 }
221
nanoappEnd(void)222 extern "C" void nanoappEnd(void) {
223 if (!chreSensorConfigureModeOnly(gSensorHandle,
224 CHRE_SENSOR_CONFIGURE_MODE_DONE)) {
225 sendFatalFailureToHost("Unable to configure sensor mode to DONE");
226 }
227
228 if (gInMethod) {
229 // This message won't be noticed by the host; but hopefully the
230 // fatal failure prevents a clean unload of the app and fails the test.
231 sendFatalFailureToHost("nanoappEnd called in reentrant manner");
232 }
233 }
234