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