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/macros.h>
50 #include <shared/send_message.h>
51 #include <shared/test_success_marker.h>
52 #include <shared/time_util.h>
53 #include "chre_api/chre.h"
54
55 #define LOG_TAG "[BusyStartup]"
56
57 using nanoapp_testing::MessageType;
58
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 EXPECT_FAIL_RETURN("Event from self, bad event type:", &e);
88 }
89 if (eventData == nullptr) {
90 EXPECT_FAIL_RETURN("Event from self, null data");
91 }
92 if (*eventData != gInstanceId) {
93 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("TimerEvent, null data");
101 }
102 if (*eventData != gInstanceId) {
103 EXPECT_FAIL_RETURN("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 EXPECT_FAIL_RETURN("sensorEvent, null data");
113 }
114 if (header->sensorHandle != gSensorHandle) {
115 EXPECT_FAIL_RETURN("sensorEvent for wrong handle", &header->sensorHandle);
116 }
117 if (header->readingCount == 0) {
118 EXPECT_FAIL_RETURN("sensorEvent has readingCount of 0");
119 }
120 if (header->reserved != 0) {
121 EXPECT_FAIL_RETURN("sensorEvent has non-zero reserved field");
122 }
123
124 if (chreGetApiVersion() < CHRE_API_VERSION_1_3) {
125 if (header->accuracy != 0) {
126 EXPECT_FAIL_RETURN("sensorEvent has non-zero reserved field");
127 }
128 } else if (header->accuracy > CHRE_SENSOR_ACCURACY_HIGH) {
129 EXPECT_FAIL_RETURN_UINT8("Sensor accuracy is not within valid range: ",
130 header->accuracy);
131 }
132
133 gTestSuccessMarker.markStageAndSuccessOnFinish(BUSY_STARTUP_STAGE_SENSOR);
134 }
135
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)136 extern "C" void nanoappHandleEvent(uint32_t senderInstanceId,
137 uint16_t eventType, const void *eventData) {
138 if (gInMethod) {
139 EXPECT_FAIL_RETURN("CHRE reentered nanoapp");
140 }
141 gInMethod = true;
142 const uint32_t *intData = static_cast<const uint32_t *>(eventData);
143 if (senderInstanceId == gInstanceId) {
144 checkSelfEvent(eventType, intData);
145
146 } else if (senderInstanceId == CHRE_INSTANCE_ID) {
147 if (eventType == CHRE_EVENT_TIMER) {
148 checkTimerEvent(intData);
149 } else if (eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_DATA) {
150 checkSensorEvent(eventData);
151 } else if (eventType == CHRE_EVENT_SENSOR_SAMPLING_CHANGE ||
152 eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO) {
153 // This could have been generated when we configured the
154 // sensor. We just ignore it.
155 } else {
156 uint32_t e = eventType;
157 EXPECT_FAIL_RETURN("Unexpected event from CHRE:", &e);
158 }
159 } else {
160 EXPECT_FAIL_RETURN("Unexpected senderInstanceId", &senderInstanceId);
161 }
162 gInMethod = false;
163 }
164
nanoappStart(void)165 extern "C" bool nanoappStart(void) {
166 gInMethod = true;
167 void *ptr = chreHeapAlloc(15);
168 if (ptr == nullptr) {
169 // TODO(b/32326854): We're not able to send messages from
170 // nanoappStart(), so we just use LOGE() here, and make
171 // the user look through the logs to determine why this failed.
172 LOGE("Unable to malloc in start");
173 return false;
174 }
175 gInstanceId = chreGetInstanceId();
176 if (gInstanceId == CHRE_INSTANCE_ID) {
177 LOGE("Got bad instance ID in start");
178 return false;
179 }
180
181 // Send an event to ourself.
182 if (!chreSendEvent(kEventType, &gInstanceId, nullptr, gInstanceId)) {
183 LOGE("Failed chreSendEvent in start");
184 return false;
185 }
186
187 // One shot timer that should trigger very quickly.
188 gTimerId = chreTimerSet(1, &gInstanceId, true);
189 if (gTimerId == CHRE_TIMER_INVALID) {
190 LOGE("Failed chreTimerSet in start");
191 return false;
192 }
193
194 // We don't have a way to confirm the 'free' worked, we'll just look
195 // to see that we didn't crash. We intentionally move this 'free' to
196 // be not immediately after the 'alloc', and still before we're done
197 // calling other methods.
198 chreHeapFree(ptr);
199
200 // Confirm we can find and configure a sensor.
201 if (!chreSensorFindDefault(CHRE_SENSOR_TYPE_ACCELEROMETER, &gSensorHandle)) {
202 LOGE("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, CHRE_SENSOR_CONFIGURE_MODE_CONTINUOUS,
209 20 * nanoapp_testing::kOneMillisecondInNanoseconds,
210 CHRE_SENSOR_LATENCY_ASAP)) {
211 LOGE("Failed sensorConfigure in start");
212 return false;
213 }
214
215 // TODO(b/32326854): Confirm we can send a message to the host.
216
217 gInMethod = false;
218 return true;
219 }
220
nanoappEnd(void)221 extern "C" void nanoappEnd(void) {
222 if (!chreSensorConfigureModeOnly(gSensorHandle,
223 CHRE_SENSOR_CONFIGURE_MODE_DONE)) {
224 EXPECT_FAIL_RETURN("Unable to configure sensor mode to DONE");
225 }
226
227 if (gInMethod) {
228 // This message won't be noticed by the host; but hopefully the
229 // fatal failure prevents a clean unload of the app and fails the test.
230 EXPECT_FAIL_RETURN("nanoappEnd called in reentrant manner");
231 }
232 }
233