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