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 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 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 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. 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 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(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. 97 static void *prependMessageType(MessageType messageType, void *memory) { 98 if (!needToPrependMessageType()) { 99 return memory; 100 } 101 uint32_t type = nanoapp_testing::hostToLittleEndian( 102 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 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 (!chreSendMessageToHostEndpoint(data, dataSize, 115 static_cast<uint32_t>(messageType), 116 CHRE_HOST_ENDPOINT_BROADCAST, 117 dumbAlloc ? freeDumbAllocMessage : 118 freeHeapMessage)) { 119 fatalError(); 120 } 121 } 122 123 void sendMessageToHost(MessageType messageType, const void *data, 124 size_t dataSize) { 125 if ((dataSize == 0) && (data != nullptr)) { 126 sendInternalFailureToHost("Bad sendMessageToHost args"); 127 } 128 bool dumbAlloc = true; 129 size_t fullMessageSize = dataSize; 130 void *myMessageBase = getMessageMemory(&fullMessageSize, &dumbAlloc); 131 void *ptr = prependMessageType(messageType, myMessageBase); 132 memcpy(ptr, data, dataSize); 133 internalSendMessage(messageType, myMessageBase, fullMessageSize, dumbAlloc); 134 } 135 136 void sendStringToHost(MessageType messageType, const char *message, 137 const uint32_t *value) { 138 if (message == nullptr) { 139 sendInternalFailureToHost("sendStringToHost 'message' is NULL"); 140 } 141 bool dumbAlloc = true; 142 const size_t messageStrlen = strlen(message); 143 size_t myMessageLen = messageStrlen; 144 if (value != nullptr) { 145 myMessageLen += kUint32ToHexAsciiBufferMinLen; 146 } 147 // Add null terminator 148 myMessageLen++; 149 150 size_t fullMessageLen = myMessageLen; 151 char *fullMessage = 152 static_cast<char*>(getMessageMemory(&fullMessageLen, &dumbAlloc)); 153 char *ptr = static_cast<char*>(prependMessageType(messageType, 154 fullMessage)); 155 memcpy(ptr, message, messageStrlen); 156 ptr += messageStrlen; 157 if (value != nullptr) { 158 uint32ToHexAscii( 159 ptr, fullMessageLen - static_cast<size_t>(ptr - fullMessage), *value); 160 } 161 // Add the terminator. 162 fullMessage[fullMessageLen - 1] = '\0'; 163 164 internalSendMessage(messageType, fullMessage, fullMessageLen, dumbAlloc); 165 } 166 167 // Before we abort the nanoapp, we also put this message in the chreLog(). 168 // We have no assurance our message will make it to the Host (not required 169 // for CHRE implementations), but this will at least make sure our message 170 // hits the log. 171 static void logFatalMessage(const char *message, const uint32_t *value) { 172 if (value != nullptr) { 173 chreLog(CHRE_LOG_ERROR, "TEST ABORT: %s0x%08" PRIX32, message, *value); 174 } else { 175 chreLog(CHRE_LOG_ERROR, "TEST ABORT: %s", message); 176 } 177 } 178 179 void sendFatalFailureToHost(const char *message, const uint32_t *value, 180 AbortBlame reason) { 181 sendFailureToHost(message, value); 182 logFatalMessage(message, value); 183 nanoapp_testing::abort(reason); 184 } 185 186 void sendInternalFailureToHost(const char *message, const uint32_t *value, 187 AbortBlame reason) { 188 sendStringToHost(MessageType::kInternalFailure, message, value); 189 logFatalMessage(message, value); 190 nanoapp_testing::abort(reason); 191 } 192 193 } // namespace nanoapp_testing 194