1 /* 2 * Copyright (C) 2017 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 <cinttypes> 18 #include <type_traits> 19 20 #include "chre/core/event_loop_manager.h" 21 #include "chre/core/host_comms_manager.h" 22 #include "chre/platform/assert.h" 23 #include "chre/platform/host_link.h" 24 25 namespace chre { 26 27 constexpr uint32_t kMessageToHostReservedFieldValue = UINT32_MAX; 28 29 void HostCommsManager::flushMessagesSentByNanoapp(uint64_t appId) { 30 mHostLink.flushMessagesSentByNanoapp(appId); 31 } 32 33 void HostCommsManager::sendLogMessage(const char *logMessage, 34 size_t logMessageSize) { 35 mHostLink.sendLogMessage(logMessage, logMessageSize); 36 } 37 38 bool HostCommsManager::sendMessageToHostFromNanoapp( 39 Nanoapp *nanoapp, void *messageData, size_t messageSize, 40 uint32_t messageType, uint16_t hostEndpoint, 41 chreMessageFreeFunction *freeCallback) { 42 bool success = false; 43 if (messageSize > 0 && messageData == nullptr) { 44 LOGW("Rejecting malformed message (null data but non-zero size)"); 45 } else if (messageSize > CHRE_MESSAGE_TO_HOST_MAX_SIZE) { 46 LOGW("Rejecting message of size %zu bytes (max %d)", messageSize, 47 CHRE_MESSAGE_TO_HOST_MAX_SIZE); 48 } else if (hostEndpoint == kHostEndpointUnspecified) { 49 LOGW("Rejecting message to invalid host endpoint"); 50 } else { 51 MessageToHost *msgToHost = mMessagePool.allocate(); 52 53 if (msgToHost == nullptr) { 54 LOG_OOM(); 55 } else { 56 msgToHost->appId = nanoapp->getAppId(); 57 msgToHost->message.wrap(static_cast<uint8_t *>(messageData), messageSize); 58 msgToHost->toHostData.hostEndpoint = hostEndpoint; 59 msgToHost->toHostData.messageType = messageType; 60 msgToHost->toHostData.nanoappFreeFunction = freeCallback; 61 62 // Populate a special value to help disambiguate message direction when 63 // debugging 64 msgToHost->toHostData.reserved = kMessageToHostReservedFieldValue; 65 66 // Let the nanoapp know that it woke up the host and record it 67 bool hostWasAwake = EventLoopManagerSingleton::get() 68 ->getEventLoop() 69 .getPowerControlManager() 70 .hostIsAwake(); 71 72 success = mHostLink.sendMessage(msgToHost); 73 if (!success) { 74 mMessagePool.deallocate(msgToHost); 75 } else if (!hostWasAwake && !mIsNanoappBlamedForWakeup) { 76 // If message successfully sent and host was suspended before sending 77 EventLoopManagerSingleton::get() 78 ->getEventLoop() 79 .handleNanoappWakeupBuckets(); 80 mIsNanoappBlamedForWakeup = true; 81 nanoapp->blameHostWakeup(); 82 } 83 } 84 } 85 86 return success; 87 } 88 89 MessageFromHost *HostCommsManager::craftNanoappMessageFromHost( 90 uint64_t appId, uint16_t hostEndpoint, uint32_t messageType, 91 const void *messageData, uint32_t messageSize) { 92 MessageFromHost *msgFromHost = mMessagePool.allocate(); 93 if (msgFromHost == nullptr) { 94 LOG_OOM(); 95 } else if (!msgFromHost->message.copy_array( 96 static_cast<const uint8_t *>(messageData), messageSize)) { 97 LOGE("Couldn't allocate %" PRIu32 98 " bytes for message data from host " 99 "(endpoint 0x%" PRIx16 " type %" PRIu32 ")", 100 messageSize, hostEndpoint, messageType); 101 mMessagePool.deallocate(msgFromHost); 102 msgFromHost = nullptr; 103 } else { 104 msgFromHost->appId = appId; 105 msgFromHost->fromHostData.messageType = messageType; 106 msgFromHost->fromHostData.messageSize = messageSize; 107 msgFromHost->fromHostData.message = msgFromHost->message.data(); 108 msgFromHost->fromHostData.hostEndpoint = hostEndpoint; 109 } 110 111 return msgFromHost; 112 } 113 114 bool HostCommsManager::deliverNanoappMessageFromHost( 115 MessageFromHost *craftedMessage) { 116 const EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop(); 117 uint32_t targetInstanceId; 118 bool success = false; 119 120 CHRE_ASSERT_LOG(craftedMessage != nullptr, 121 "Cannot deliver NULL pointer nanoapp message from host"); 122 123 if (eventLoop.findNanoappInstanceIdByAppId(craftedMessage->appId, 124 &targetInstanceId)) { 125 success = true; 126 if (!EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( 127 CHRE_EVENT_MESSAGE_FROM_HOST, &craftedMessage->fromHostData, 128 freeMessageFromHostCallback, targetInstanceId)) { 129 mMessagePool.deallocate(craftedMessage); 130 } 131 } 132 133 return success; 134 } 135 136 void HostCommsManager::sendMessageToNanoappFromHost(uint64_t appId, 137 uint32_t messageType, 138 uint16_t hostEndpoint, 139 const void *messageData, 140 size_t messageSize) { 141 if (hostEndpoint == kHostEndpointBroadcast) { 142 LOGE("Received invalid message from host from broadcast endpoint"); 143 } else if (messageSize > ((UINT32_MAX))) { 144 // The current CHRE API uses uint32_t to represent the message size in 145 // struct chreMessageFromHostData. We don't expect to ever need to exceed 146 // this, but the check ensures we're on the up and up. 147 LOGE("Rejecting message of size %zu (too big)", messageSize); 148 } else { 149 MessageFromHost *craftedMessage = craftNanoappMessageFromHost( 150 appId, hostEndpoint, messageType, messageData, 151 static_cast<uint32_t>(messageSize)); 152 if (craftedMessage == nullptr) { 153 LOGE("Out of memory - rejecting message to app ID 0x%016" PRIx64 154 "(size %zu)", 155 appId, messageSize); 156 } else if (!deliverNanoappMessageFromHost(craftedMessage)) { 157 LOGD("Deferring message; destination app ID 0x%016" PRIx64 158 " not found at this time", 159 appId); 160 161 auto deferredMessageCallback = [](uint16_t /*type*/, void *data) { 162 EventLoopManagerSingleton::get() 163 ->getHostCommsManager() 164 .sendDeferredMessageToNanoappFromHost( 165 static_cast<MessageFromHost *>(data)); 166 }; 167 EventLoopManagerSingleton::get()->deferCallback( 168 SystemCallbackType::DeferredMessageToNanoappFromHost, craftedMessage, 169 deferredMessageCallback); 170 } 171 } 172 } 173 174 void HostCommsManager::sendDeferredMessageToNanoappFromHost( 175 MessageFromHost *craftedMessage) { 176 CHRE_ASSERT_LOG(craftedMessage != nullptr, 177 "Deferred message from host is a NULL pointer"); 178 179 if (!deliverNanoappMessageFromHost(craftedMessage)) { 180 LOGE("Dropping deferred message; destination app ID 0x%016" PRIx64 181 " still not found", 182 craftedMessage->appId); 183 mMessagePool.deallocate(craftedMessage); 184 } else { 185 LOGD("Deferred message to app ID 0x%016" PRIx64 " delivered", 186 craftedMessage->appId); 187 } 188 } 189 190 void HostCommsManager::resetBlameForNanoappHostWakeup() { 191 mIsNanoappBlamedForWakeup = false; 192 } 193 194 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) { 195 // Removing const on message since we own the memory and will deallocate it; 196 // the caller (HostLink) only gets a const pointer 197 auto *msgToHost = const_cast<MessageToHost *>(message); 198 199 // If there's no free callback, we can free the message right away as the 200 // message pool is thread-safe; otherwise, we need to do it from within the 201 // EventLoop context. 202 if (msgToHost->toHostData.nanoappFreeFunction == nullptr) { 203 mMessagePool.deallocate(msgToHost); 204 } else { 205 auto freeMsgCallback = [](uint16_t /*type*/, void *data) { 206 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost( 207 static_cast<MessageToHost *>(data)); 208 }; 209 210 EventLoopManagerSingleton::get()->deferCallback( 211 SystemCallbackType::MessageToHostComplete, msgToHost, freeMsgCallback); 212 } 213 } 214 215 void HostCommsManager::freeMessageToHost(MessageToHost *msgToHost) { 216 if (msgToHost->toHostData.nanoappFreeFunction != nullptr) { 217 EventLoopManagerSingleton::get()->getEventLoop().invokeMessageFreeFunction( 218 msgToHost->appId, msgToHost->toHostData.nanoappFreeFunction, 219 msgToHost->message.data(), msgToHost->message.size()); 220 } 221 mMessagePool.deallocate(msgToHost); 222 } 223 224 void HostCommsManager::freeMessageFromHostCallback(uint16_t /*type*/, 225 void *data) { 226 // We pass the chreMessageFromHostData structure to the nanoapp as the event's 227 // data pointer, but we need to return to the enclosing HostMessage pointer. 228 // As long as HostMessage is standard-layout, and fromHostData is the first 229 // field, we can convert between these two pointers via reinterpret_cast. 230 // These static assertions ensure this assumption is held. 231 static_assert(std::is_standard_layout<HostMessage>::value, 232 "HostMessage* is derived from HostMessage::fromHostData*, " 233 "therefore it must be standard layout"); 234 static_assert(offsetof(MessageFromHost, fromHostData) == 0, 235 "fromHostData must be the first field in HostMessage"); 236 237 auto *eventData = static_cast<chreMessageFromHostData *>(data); 238 auto *msgFromHost = reinterpret_cast<MessageFromHost *>(eventData); 239 auto &hostCommsMgr = EventLoopManagerSingleton::get()->getHostCommsManager(); 240 hostCommsMgr.mMessagePool.deallocate(msgFromHost); 241 } 242 243 } // namespace chre 244