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