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