Home | History | Annotate | Download | only in shared
      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