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.h>
27
28 namespace nanoapp_testing {
29
30 constexpr size_t kAllocSize = 128;
31
32 static ChunkAllocator<kAllocSize, 4> gChunkAlloc;
33
freeChunkAllocMessage(void * message,size_t messageSize)34 static void freeChunkAllocMessage(void *message, size_t messageSize) {
35 if (messageSize > kAllocSize) {
36 uint32_t localSize = uint32_t(messageSize);
37 sendFatalFailureToHost("freeChunkAllocMessage given oversized message:",
38 &localSize);
39 }
40 if (!gChunkAlloc.free(message)) {
41 uint32_t localPtr =
42 reinterpret_cast<size_t>(message) & UINT32_C(0xFFFFFFFF);
43 sendFatalFailureToHost("freeChunkAllocMessage given bad pointer:",
44 &localPtr);
45 }
46 }
47
freeHeapMessage(void * message,size_t)48 static void freeHeapMessage(void *message, size_t /* messageSize */) {
49 if (gChunkAlloc.contains(message)) {
50 uint32_t localPtr =
51 reinterpret_cast<size_t>(message) & UINT32_C(0xFFFFFFFF);
52 sendFatalFailureToHost("freeHeapMessage given ChunkAlloc 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 chreSendMessageToHostEndpoint(nullptr, 0,
62 static_cast<uint32_t>(MessageType::kFailure),
63 CHRE_HOST_ENDPOINT_BROADCAST, 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 * ChunkAlloc)77 static void *getMessageMemory(size_t *size, bool *ChunkAlloc) {
78 if (needToPrependMessageType()) {
79 *size += sizeof(uint32_t);
80 }
81 void *ret = gChunkAlloc.alloc(*size);
82 if (ret != nullptr) {
83 *ChunkAlloc = 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 *ChunkAlloc = false;
88 ret = chreHeapAlloc(static_cast<uint32_t>(*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 =
102 nanoapp_testing::hostToLittleEndian(static_cast<uint32_t>(messageType));
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 ChunkAlloc)109 static void internalSendMessage(MessageType messageType, void *data,
110 size_t dataSize, bool ChunkAlloc) {
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 (!chreSendMessageToHostEndpoint(
115 data, dataSize, static_cast<uint32_t>(messageType),
116 CHRE_HOST_ENDPOINT_BROADCAST,
117 ChunkAlloc ? freeChunkAllocMessage : 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 ChunkAlloc = true;
128 size_t fullMessageSize = dataSize;
129 void *myMessageBase = getMessageMemory(&fullMessageSize, &ChunkAlloc);
130 void *ptr = prependMessageType(messageType, myMessageBase);
131 memcpy(ptr, data, dataSize);
132 internalSendMessage(messageType, myMessageBase, fullMessageSize, ChunkAlloc);
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 ChunkAlloc = 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, &ChunkAlloc));
152 char *ptr = static_cast<char *>(prependMessageType(messageType, fullMessage));
153 memcpy(ptr, message, messageStrlen);
154 ptr += messageStrlen;
155 if (value != nullptr) {
156 uint32ToHexAscii(
157 ptr, fullMessageLen - static_cast<size_t>(ptr - fullMessage), *value);
158 }
159 // Add the terminator.
160 fullMessage[fullMessageLen - 1] = '\0';
161
162 internalSendMessage(messageType, fullMessage, fullMessageLen, ChunkAlloc);
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
sendFatalFailureToHostUint8(const char * message,uint8_t value)184 void sendFatalFailureToHostUint8(const char *message, uint8_t value) {
185 uint32_t val = value;
186 sendFatalFailureToHost(message, &val);
187 }
188
sendInternalFailureToHost(const char * message,const uint32_t * value,AbortBlame reason)189 void sendInternalFailureToHost(const char *message, const uint32_t *value,
190 AbortBlame reason) {
191 sendStringToHost(MessageType::kInternalFailure, message, value);
192 logFatalMessage(message, value);
193 nanoapp_testing::abort(reason);
194 }
195
196 } // namespace nanoapp_testing
197