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