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 consistency check that
23 * calling 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 chreSendMessageToHostEndpoint() [**]
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/util/nanoapp/log.h>
48
49 #include <shared/send_message.h>
50 #include <shared/test_success_marker.h>
51 #include <shared/time_util.h>
52 #include "chre_api/chre.h"
53
54 #define LOG_TAG "[BusyStartup]"
55
56 using nanoapp_testing::MessageType;
57 using nanoapp_testing::sendFatalFailureToHost;
58 using nanoapp_testing::sendFatalFailureToHostUint8;
59 using nanoapp_testing::sendMessageToHost;
60 using nanoapp_testing::sendSuccessToHost;
61 using nanoapp_testing::TestSuccessMarker;
62
63 static bool gInMethod = false;
64 static uint32_t gInstanceId;
65 static uint32_t gTimerId;
66 static uint32_t gSensorHandle;
67
68 /**
69 * Busy startup stages and total number of stages.
70 */
71 enum BusyStartupStage {
72 BUSY_STARTUP_STAGE_SELF_EVENT = 0,
73 BUSY_STARTUP_STAGE_TIMER,
74 BUSY_STARTUP_STAGE_SENSOR,
75 BUSY_STARTUP_STAGE_COUNT,
76 };
77
78 //! TestSuccessMarker object to mark success of a stage.
79 TestSuccessMarker gTestSuccessMarker =
80 TestSuccessMarker(BUSY_STARTUP_STAGE_COUNT);
81
82 constexpr uint16_t kEventType = CHRE_EVENT_FIRST_USER_VALUE;
83
checkSelfEvent(uint16_t eventType,const uint32_t * eventData)84 static void checkSelfEvent(uint16_t eventType, const uint32_t *eventData) {
85 if (eventType != kEventType) {
86 uint32_t e = eventType;
87 sendFatalFailureToHost("Event from self, bad event type:", &e);
88 }
89 if (eventData == nullptr) {
90 sendFatalFailureToHost("Event from self, null data");
91 }
92 if (*eventData != gInstanceId) {
93 sendFatalFailureToHost("Event from self, bad data:", eventData);
94 }
95 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_SELF_EVENT);
96 }
97
checkTimerEvent(const uint32_t * eventData)98 static void checkTimerEvent(const uint32_t *eventData) {
99 if (eventData == nullptr) {
100 sendFatalFailureToHost("TimerEvent, null data");
101 }
102 if (*eventData != gInstanceId) {
103 sendFatalFailureToHost("TimerEvent, bad data:", eventData);
104 }
105 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_TIMER);
106 }
107
checkSensorEvent(const void * eventData)108 static void checkSensorEvent(const void *eventData) {
109 const chreSensorDataHeader *header =
110 static_cast<const chreSensorDataHeader *>(eventData);
111 if (header == nullptr) {
112 sendFatalFailureToHost("sensorEvent, null data");
113 }
114 if (header->sensorHandle != gSensorHandle) {
115 sendFatalFailureToHost("sensorEvent for wrong handle",
116 &header->sensorHandle);
117 }
118 if (header->readingCount == 0) {
119 sendFatalFailureToHost("sensorEvent has readingCount of 0");
120 }
121 if (header->reserved != 0) {
122 sendFatalFailureToHost("sensorEvent has non-zero reserved field");
123 }
124
125 if (chreGetApiVersion() < CHRE_API_VERSION_1_3) {
126 if (header->accuracy != 0) {
127 sendFatalFailureToHost("sensorEvent has non-zero reserved field");
128 }
129 } else if (header->accuracy > CHRE_SENSOR_ACCURACY_HIGH) {
130 sendFatalFailureToHostUint8("Sensor accuracy is not within valid range: ",
131 header->accuracy);
132 }
133
134 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_SENSOR);
135 }
136
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)137 extern "C" void nanoappHandleEvent(uint32_t senderInstanceId,
138 uint16_t eventType, const void *eventData) {
139 if (gInMethod) {
140 sendFatalFailureToHost("CHRE reentered nanoapp");
141 }
142 gInMethod = true;
143 const uint32_t *intData = static_cast<const uint32_t *>(eventData);
144 if (senderInstanceId == gInstanceId) {
145 checkSelfEvent(eventType, intData);
146
147 } else if (senderInstanceId == CHRE_INSTANCE_ID) {
148 if (eventType == CHRE_EVENT_TIMER) {
149 checkTimerEvent(intData);
150 } else if (eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_DATA) {
151 checkSensorEvent(eventData);
152 } else if (eventType == CHRE_EVENT_SENSOR_SAMPLING_CHANGE ||
153 eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO) {
154 // This could have been generated when we configured the
155 // sensor. We just ignore it.
156 } else {
157 uint32_t e = eventType;
158 sendFatalFailureToHost("Unexpected event from CHRE:", &e);
159 }
160 } else {
161 sendFatalFailureToHost("Unexpected senderInstanceId", &senderInstanceId);
162 }
163 gInMethod = false;
164 }
165
nanoappStart(void)166 extern "C" bool nanoappStart(void) {
167 gInMethod = true;
168 void *ptr = chreHeapAlloc(15);
169 if (ptr == nullptr) {
170 // TODO(b/32326854): We're not able to send messages from
171 // nanoappStart(), so we just use LOGE() here, and make
172 // the user look through the logs to determine why this failed.
173 LOGE("Unable to malloc in start");
174 return false;
175 }
176 gInstanceId = chreGetInstanceId();
177 if (gInstanceId == CHRE_INSTANCE_ID) {
178 LOGE("Got bad instance ID in start");
179 return false;
180 }
181
182 // Send an event to ourself.
183 if (!chreSendEvent(kEventType, &gInstanceId, nullptr, gInstanceId)) {
184 LOGE("Failed chreSendEvent in start");
185 return false;
186 }
187
188 // One shot timer that should trigger very quickly.
189 gTimerId = chreTimerSet(1, &gInstanceId, true);
190 if (gTimerId == CHRE_TIMER_INVALID) {
191 LOGE("Failed chreTimerSet in start");
192 return false;
193 }
194
195 // We don't have a way to confirm the 'free' worked, we'll just look
196 // to see that we didn't crash. We intentionally move this 'free' to
197 // be not immediately after the 'alloc', and still before we're done
198 // calling other methods.
199 chreHeapFree(ptr);
200
201 // Confirm we can find and configure a sensor.
202 if (!chreSensorFindDefault(CHRE_SENSOR_TYPE_ACCELEROMETER, &gSensorHandle)) {
203 LOGE("Failed sensorFindDefault in start");
204 return false;
205 }
206
207 // Configure accel request at 50 Hz (reasonable rate, e.g. for AR)
208 // TODO: Add a way to find the range of possible sample rates
209 if (!chreSensorConfigure(gSensorHandle, CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS,
210 20 * nanoapp_testing::kOneMillisecondInNanoseconds,
211 CHRE_SENSOR_LATENCY_ASAP)) {
212 LOGE("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