• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <shared/send_message.h>
18 
19 #include <inttypes.h>
20 
21 #include <shared/abort.h>
22 #include <shared/dumb_allocator.h>
23 #include <shared/nano_endian.h>
24 #include <shared/nano_string.h>
25 
26 #include <chre.h>
27 
28 namespace nanoapp_testing {
29 
30 constexpr size_t kAllocSize = 128;
31 
32 static DumbAllocator<kAllocSize, 4> gDumbAlloc;
33 
freeDumbAllocMessage(void * message,size_t messageSize)34 static void freeDumbAllocMessage(void *message, size_t messageSize) {
35   if (messageSize > kAllocSize) {
36     uint32_t localSize = uint32_t(messageSize);
37     sendFatalFailureToHost("freeDumbAllocMessage given oversized message:",
38                            &localSize);
39   }
40   if (!gDumbAlloc.free(message)) {
41     uint32_t localPtr =
42         reinterpret_cast<size_t>(message) & UINT32_C(0xFFFFFFFF);
43     sendFatalFailureToHost("freeDumbAllocMessage given bad pointer:",
44                            &localPtr);
45   }
46 }
47 
freeHeapMessage(void * message,size_t)48 static void freeHeapMessage(void *message, size_t /* messageSize */) {
49   if (gDumbAlloc.contains(message)) {
50     uint32_t localPtr =
51         reinterpret_cast<size_t>(message) & UINT32_C(0xFFFFFFFF);
52     sendFatalFailureToHost("freeHeapMessage given DumbAlloc pointer:",
53                            &localPtr);
54   }
55   chreHeapFree(message);
56 }
57 
fatalError()58 static void fatalError() {
59   // Attempt to send a context-less failure message, in the hopes that
60   // might get through.
61   chreSendMessageToHost(nullptr, 0,
62                         static_cast<uint32_t>(MessageType::kFailure),
63                         nullptr);
64   // Whether or not that made it through, unambigiously fail this test
65   // by aborting.
66   nanoapp_testing::abort();
67 }
68 
69 // TODO(b/32114261): Remove this method.
needToPrependMessageType()70 static bool needToPrependMessageType() {
71   // TODO: When we have a new API that properly send the messageType,
72   //     this method should get the API version and return appropriately.
73   //     Eventually we should remove this hacky method.
74   return true;
75 }
76 
getMessageMemory(size_t * size,bool * dumbAlloc)77 static void *getMessageMemory(size_t *size, bool *dumbAlloc) {
78   if (needToPrependMessageType()) {
79     *size += sizeof(uint32_t);
80   }
81   void *ret = gDumbAlloc.alloc(*size);
82   if (ret != nullptr) {
83     *dumbAlloc = true;
84   } else {
85     // Not expected, but possible if the CHRE is lagging in freeing
86     // these messages, or if we're sending a huge message.
87     *dumbAlloc = false;
88     ret = chreHeapAlloc(*size);
89     if (ret == nullptr) {
90       fatalError();
91     }
92   }
93   return ret;
94 }
95 
96 // TODO(b/32114261): Remove this method.
prependMessageType(MessageType messageType,void * memory)97 static void *prependMessageType(MessageType messageType, void *memory) {
98   if (!needToPrependMessageType()) {
99     return memory;
100   }
101   uint32_t type = static_cast<uint32_t>(messageType);
102   nanoapp_testing::hostToLittleEndian(&type);
103   memcpy(memory, &type, sizeof(type));
104   uint8_t *ptr = static_cast<uint8_t*>(memory);
105   ptr += sizeof(type);
106   return ptr;
107 }
108 
internalSendMessage(MessageType messageType,void * data,size_t dataSize,bool dumbAlloc)109 static void internalSendMessage(MessageType messageType, void *data,
110                                 size_t dataSize, bool dumbAlloc) {
111   // Note that if the CHRE implementation occasionally drops a message
112   // here, then tests will become flaky.  For now, we consider that to
113   // be a flaky CHRE implementation which should fail testing.
114   if (!chreSendMessageToHost(data, dataSize,
115                              static_cast<uint32_t>(messageType),
116                              dumbAlloc ? freeDumbAllocMessage :
117                              freeHeapMessage)) {
118     fatalError();
119   }
120 }
121 
sendMessageToHost(MessageType messageType,const void * data,size_t dataSize)122 void sendMessageToHost(MessageType messageType, const void *data,
123                        size_t dataSize) {
124   if ((dataSize == 0) && (data != nullptr)) {
125     sendInternalFailureToHost("Bad sendMessageToHost args");
126   }
127   bool dumbAlloc = true;
128   size_t fullMessageSize = dataSize;
129   void *myMessageBase = getMessageMemory(&fullMessageSize, &dumbAlloc);
130   void *ptr = prependMessageType(messageType, myMessageBase);
131   memcpy(ptr, data, dataSize);
132   internalSendMessage(messageType, myMessageBase, fullMessageSize, dumbAlloc);
133 }
134 
sendStringToHost(MessageType messageType,const char * message,const uint32_t * value)135 void sendStringToHost(MessageType messageType, const char *message,
136                       const uint32_t *value) {
137   if (message == nullptr) {
138     sendInternalFailureToHost("sendStringToHost 'message' is NULL");
139   }
140   bool dumbAlloc = true;
141   const size_t messageStrlen = strlen(message);
142   size_t myMessageLen = messageStrlen;
143   if (value != nullptr) {
144     myMessageLen += kUint32ToHexAsciiBufferMinLen;
145   }
146   // Add null terminator
147   myMessageLen++;
148 
149   size_t fullMessageLen = myMessageLen;
150   char *fullMessage =
151       static_cast<char*>(getMessageMemory(&fullMessageLen, &dumbAlloc));
152   char *ptr = static_cast<char*>(prependMessageType(messageType,
153                                                     fullMessage));
154   memcpy(ptr, message, messageStrlen);
155   ptr += messageStrlen;
156   if (value != nullptr) {
157     uint32ToHexAscii(ptr, fullMessageLen - (ptr - fullMessage), *value);
158   }
159   // Add the terminator.
160   fullMessage[fullMessageLen - 1] = '\0';
161 
162   internalSendMessage(messageType, fullMessage, fullMessageLen, dumbAlloc);
163 }
164 
165 // Before we abort the nanoapp, we also put this message in the chreLog().
166 // We have no assurance our message will make it to the Host (not required
167 // for CHRE implementations), but this will at least make sure our message
168 // hits the log.
logFatalMessage(const char * message,const uint32_t * value)169 static void logFatalMessage(const char *message, const uint32_t *value) {
170   if (value != nullptr) {
171     chreLog(CHRE_LOG_ERROR, "TEST ABORT: %s0x%08" PRIX32, message, *value);
172   } else {
173     chreLog(CHRE_LOG_ERROR, "TEST ABORT: %s", message);
174   }
175 }
176 
sendFatalFailureToHost(const char * message,const uint32_t * value,AbortBlame reason)177 void sendFatalFailureToHost(const char *message, const uint32_t *value,
178                             AbortBlame reason) {
179   sendFailureToHost(message, value);
180   logFatalMessage(message, value);
181   nanoapp_testing::abort(reason);
182 }
183 
sendInternalFailureToHost(const char * message,const uint32_t * value,AbortBlame reason)184 void sendInternalFailureToHost(const char *message, const uint32_t *value,
185                                AbortBlame reason) {
186   sendStringToHost(MessageType::kInternalFailure, message, value);
187   logFatalMessage(message, value);
188   nanoapp_testing::abort(reason);
189 }
190 
191 }  // namespace nanoapp_testing
192