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