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(*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 = 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 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 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 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. 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 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 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