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(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