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