1 /*
2 * Copyright (C) 2016 The 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 #include <general_test/send_message_to_host_test.h>
18
19 #include <cinttypes>
20 #include <cstddef>
21
22 #include <shared/nano_endian.h>
23 #include <shared/nano_string.h>
24 #include <shared/send_message.h>
25
26 #include <chre.h>
27
28 using nanoapp_testing::MessageType;
29 using nanoapp_testing::sendFatalFailureToHost;
30 using nanoapp_testing::sendInternalFailureToHost;
31 using nanoapp_testing::sendSuccessToHost;
32
33
34 /*
35 * Our test essentially has nine stages. The first eight stages all involve
36 * sending data to the Host. Here is a table describing them:
37 *
38 * Stage | Data length | Callback
39 * ------|-------------|--------------
40 * 0 | small | smallMessage0
41 * 1 | small | smallMessage1
42 * 2 | small | nullptr
43 * 3 | small | smallMessage0
44 * 4 | nullptr | nullptr
45 * 5 | 4 bytes | nullptr
46 * 6 | MAX + 1 | largeMessage
47 * 7 | MAX | largeMessage
48 *
49 * Stage 8 involves waiting for an incoming zero-sized message from the Host.
50 *
51 * The focus of the first four stages is making sure the correct callback
52 * gets invoked and a nullptr callback works.
53 *
54 * Stage 4 tests sending a null message to the Host (that should send).
55 *
56 * Stage 5 is not testing anything, but it's necessary to get data
57 * to the host to confirm the message in stage 7 is correct.
58 *
59 * Stage 6 tests that we properly reject oversized messages. This
60 * data should _not_ make it to the host.
61 *
62 * Stage 7 tests that we can send the maximum claimed size to the host.
63 *
64 * Every single stage which has a non-null callback is not considered a
65 * "success" until that callback has been invoked. There is no CHRE
66 * requirement in terms of the order in which these callbacks are
67 * invoked, which is why the markSuccess() method uses a bitmask and
68 * checks for overall success every time we gets success from a single
69 * stage.
70 *
71 * We consider the test successful only when all stages have reported success.
72 * Note that the Host will not perform Stage 8 until after it has received
73 * all the expected messages from the nanoapp. That's how we can confirm
74 * all messages actually made it through to the Host.
75 */
76
77 // TODO(b/32114261): Remove this and actually test a variety of message types.
78 constexpr uint32_t kUntestedMessageType = UINT32_C(0x51501984);
79
80 namespace general_test {
81
82 // TODO(b/32114261): Remove this variable.
83 extern bool gUseNycMessageHack;
84
85 uint8_t SendMessageToHostTest::sSmallMessageData[kSmallMessageTestCount][kSmallMessageSize];
86 void *SendMessageToHostTest::sLargeMessageData[2];
87 constexpr uint32_t SendMessageToHostTest::kLargeSizes[2];
88
89 bool SendMessageToHostTest::sInMethod = false;
90 uint32_t SendMessageToHostTest::sFinishedBitmask = 0;
91
92 template<uint8_t kCallbackIndex>
smallMessageCallback(void * message,size_t messageSize)93 void SendMessageToHostTest::smallMessageCallback(void *message,
94 size_t messageSize) {
95 if (sInMethod) {
96 sendFatalFailureToHost("smallMessageCallback called while another "
97 "nanoapp method is running");
98 }
99 sInMethod = true;
100 if (message == nullptr) {
101 sendFatalFailureToHost("smallMessageCallback given null message");
102 }
103 if (messageSize != kSmallMessageSize) {
104 uint32_t size = static_cast<uint32_t>(messageSize);
105 sendFatalFailureToHost("smallMessageCallback given bad messageSize:",
106 &size);
107 }
108 const uint8_t *msg = static_cast<const uint8_t*>(message);
109 for (size_t i = 0; i < messageSize; i++) {
110 if (msg[i] != kDataByte) {
111 sendFatalFailureToHost("Corrupt data in smallMessageCallback");
112 }
113 }
114
115 uint32_t stage = getSmallDataIndex(msg);
116 uint8_t expectedCallbackIndex = 2;
117 switch (stage) {
118 case 0: // fall-through
119 case 3:
120 expectedCallbackIndex = 0;
121 break;
122 case 1:
123 expectedCallbackIndex = 1;
124 break;
125 case 2:
126 sendFatalFailureToHost("callback invoked when null callback "
127 "given");
128 break;
129 default:
130 sendInternalFailureToHost("Invalid index", &stage);
131 }
132 if (expectedCallbackIndex != kCallbackIndex) {
133 sendFatalFailureToHost("Incorrect callback function called.");
134 }
135
136 markSuccess(stage);
137 sInMethod = false;
138 }
139
smallMessageCallback0(void * message,size_t messageSize)140 void SendMessageToHostTest::smallMessageCallback0(void *message,
141 size_t messageSize) {
142 smallMessageCallback<0>(message, messageSize);
143 }
144
smallMessageCallback1(void * message,size_t messageSize)145 void SendMessageToHostTest::smallMessageCallback1(void *message,
146 size_t messageSize) {
147 smallMessageCallback<1>(message, messageSize);
148 }
149
getSmallDataIndex(const uint8_t * data)150 uint32_t SendMessageToHostTest::getSmallDataIndex(const uint8_t *data) {
151 // O(N) is fine. N is small and this is test code.
152 for (uint32_t i = 0; i < kSmallMessageTestCount; i++) {
153 if (data == sSmallMessageData[i]) {
154 return i;
155 }
156 }
157 sendFatalFailureToHost("Bad memory sent to smallMessageCallback");
158 // We should never get here.
159 return kSmallMessageTestCount;
160 }
161
largeMessageCallback(void * message,size_t messageSize)162 void SendMessageToHostTest::largeMessageCallback(void *message,
163 size_t messageSize) {
164 if (sInMethod) {
165 sendFatalFailureToHost("largeMessageCallback called while another "
166 "nanoapp method is running");
167 }
168 sInMethod = true;
169 if (message == nullptr) {
170 sendFatalFailureToHost("largeMessageCallback given null message");
171 }
172 uint32_t index = 2;
173 if (message == sLargeMessageData[0]) {
174 index = 0;
175 } else if (message == sLargeMessageData[1]) {
176 index = 1;
177 } else {
178 sendFatalFailureToHost("largeMessageCallback given bad message");
179 }
180 if (messageSize != kLargeSizes[index]) {
181 sendFatalFailureToHost("largeMessageCallback given incorrect "
182 "messageSize");
183 }
184 const uint8_t *msg = static_cast<const uint8_t*>(message);
185 for (size_t i = 0; i < messageSize; i++) {
186 if (msg[i] != kDataByte) {
187 sendFatalFailureToHost("Corrupt data in largeMessageCallback");
188 }
189 }
190 chreHeapFree(sLargeMessageData[index]);
191 // index 0 == stage 6, index 1 == stage 7
192 markSuccess(index + 6);
193
194 sInMethod = false;
195 }
196
markSuccess(uint32_t stage)197 void SendMessageToHostTest::markSuccess(uint32_t stage) {
198 chreLog(CHRE_LOG_DEBUG, "Stage %" PRIu32 " succeeded", stage);
199 uint32_t finishedBit = (1 << stage);
200 if (sFinishedBitmask & finishedBit) {
201 sendFatalFailureToHost("callback called multiple times for stage:",
202 &stage);
203 }
204 if ((kAllFinished & finishedBit) == 0) {
205 sendFatalFailureToHost("markSuccess bad stage", &stage);
206 }
207 sFinishedBitmask |= finishedBit;
208 if (sFinishedBitmask == kAllFinished) {
209 sendSuccessToHost();
210 }
211 }
212
prepTestMemory()213 void SendMessageToHostTest::prepTestMemory() {
214 nanoapp_testing::memset(sSmallMessageData, kDataByte,
215 sizeof(sSmallMessageData));
216
217 for (size_t i = 0; i < 2; i++) {
218 sLargeMessageData[i] = chreHeapAlloc(kLargeSizes[i]);
219 if (sLargeMessageData[i] == nullptr) {
220 sendFatalFailureToHost("Insufficient heap memory for test");
221 }
222 nanoapp_testing::memset(sLargeMessageData[i], kDataByte,
223 kLargeSizes[i]);
224 }
225 }
226
sendMessageMaxSize()227 void SendMessageToHostTest::sendMessageMaxSize() {
228 // Our focus here is just sending this data; we're not trying to
229 // test anything. So we use the helper function.
230 uint32_t maxSize = nanoapp_testing::hostToLittleEndian(
231 static_cast<uint32_t>(CHRE_MESSAGE_TO_HOST_MAX_SIZE));
232 // TODO(b/32114261): We intentionally don't have a namespace using
233 // declaration for sendMessageToHost because it's generally
234 // incorrect to use while we're working around this bug. When the
235 // bug is fixed, we'll add this declaration, and use the method
236 // widely.
237 nanoapp_testing::sendMessageToHost(MessageType::kContinue,
238 &maxSize, sizeof(maxSize));
239 }
240
241 // Wrapper for chreSendMessageToHost() that sets sInMethod to false during its
242 // execution, to allow for inline callbacks (this CHRE API is allowed to call
243 // the free callback either within the function, or at an unspecified later time
244 // when this nanoapp is not otherwise executing).
sendMessageToHost(void * message,uint32_t messageSize,uint32_t reservedMessageType,chreMessageFreeFunction * freeCallback)245 bool SendMessageToHostTest::sendMessageToHost(
246 void *message, uint32_t messageSize, uint32_t reservedMessageType,
247 chreMessageFreeFunction *freeCallback) {
248 sInMethod = false;
249 bool success = chreSendMessageToHost(message, messageSize,
250 reservedMessageType, freeCallback);
251 sInMethod = true;
252
253 return success;
254 }
255
SendMessageToHostTest()256 SendMessageToHostTest::SendMessageToHostTest()
257 : Test(CHRE_API_VERSION_1_0) {
258 }
259
setUp(uint32_t messageSize,const void *)260 void SendMessageToHostTest::setUp(uint32_t messageSize,
261 const void * /* message */) {
262 // TODO(b/32114261): We need this hackery so we can get the raw bytes
263 // from the host, without the test infrastructure trying to
264 // interpret them. This won't be necessary when messageType is
265 // properly sent.
266 gUseNycMessageHack = false;
267
268 sInMethod = true;
269 if (messageSize != 0) {
270 sendFatalFailureToHost(
271 "SendMessageToHost message expects 0 additional bytes, got ",
272 &messageSize);
273 }
274
275 prepTestMemory();
276
277 // stage: 0
278 if (!sendMessageToHost(sSmallMessageData[0], kSmallMessageSize,
279 kUntestedMessageType, smallMessageCallback0)) {
280 sendFatalFailureToHost("Failed chreSendMessageToHost stage 0");
281 }
282
283 // stage: 1
284 if (!sendMessageToHost(sSmallMessageData[1], kSmallMessageSize,
285 kUntestedMessageType, smallMessageCallback1)) {
286 sendFatalFailureToHost("Failed chreSendMessageToHost stage 1");
287 }
288
289 // stage: 2
290 if (!sendMessageToHost(sSmallMessageData[2], kSmallMessageSize,
291 kUntestedMessageType, nullptr)) {
292 sendFatalFailureToHost("Failed chreSendMessageToHost stage 2");
293 }
294 // There's no callback, so we mark this as a success.
295 markSuccess(2);
296
297 // stage: 3
298 if (!sendMessageToHost(sSmallMessageData[3], kSmallMessageSize,
299 kUntestedMessageType, smallMessageCallback0)) {
300 sendFatalFailureToHost("Failed chreSendMessageToHost stage 3");
301 }
302
303 // stage: 4
304 if (!sendMessageToHost(nullptr, 0, kUntestedMessageType, nullptr)) {
305 sendFatalFailureToHost("Failed chreSendMessageToHost stage 4");
306 }
307 // There's no callback, so we mark this as a success.
308 markSuccess(4);
309
310 // stage: 5
311 sendMessageMaxSize();
312 // There's no callback, so we mark this as a success.
313 markSuccess(5);
314
315 // stage: 6
316 if (sendMessageToHost(sLargeMessageData[0], kLargeSizes[0],
317 kUntestedMessageType, largeMessageCallback)) {
318 sendFatalFailureToHost("Oversized data to chreSendMessageToHost "
319 "claimed success");
320 }
321
322 // stage: 7
323 if (!sendMessageToHost(sLargeMessageData[1], kLargeSizes[1],
324 kUntestedMessageType, largeMessageCallback)) {
325 sendFatalFailureToHost("Failed chreSendMessageToHost stage 7");
326 }
327
328 sInMethod = false;
329 }
330
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)331 void SendMessageToHostTest::handleEvent(uint32_t senderInstanceId,
332 uint16_t eventType,
333 const void* eventData) {
334 if (sInMethod) {
335 sendFatalFailureToHost("handleEvent invoked while another nanoapp "
336 "method is running");
337 }
338 sInMethod = true;
339
340 // TODO(b/32114261): Use getMessageDataFromHostEvent(). We can't do
341 // that now because our messageType is probably wrong.
342 if (senderInstanceId != CHRE_INSTANCE_ID) {
343 sendFatalFailureToHost("handleEvent got event from unexpected sender:",
344 &senderInstanceId);
345 }
346 if (eventType != CHRE_EVENT_MESSAGE_FROM_HOST) {
347 unexpectedEvent(eventType);
348 }
349
350 auto dataStruct = static_cast<const chreMessageFromHostData *>(eventData);
351 // TODO(b/32114261): Test the message type.
352 if (dataStruct->messageSize != 0) {
353 sendFatalFailureToHost("handleEvent got non-zero message size",
354 &dataStruct->messageSize);
355 }
356 // We don't test dataStruct->message. We don't require this to be
357 // nullptr. If a CHRE choses to deal in 0-sized memory blocks, that's
358 // acceptable.
359
360 // Stage 8 was successful. Note that other stages might still be waiting
361 // for freeCallbacks. So we don't send success to the host, but just
362 // mark our stage as a success.
363 markSuccess(8);
364
365 sInMethod = false;
366 }
367
368 } // namespace general_test
369