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/context.h" 24 #include "chre/platform/host_link.h" 25 26 namespace chre { 27 28 constexpr uint32_t kMessageToHostReservedFieldValue = UINT32_MAX; 29 30 bool HostCommsManager::sendMessageToHostFromCurrentNanoapp( 31 void *messageData, size_t messageSize, uint32_t messageType, 32 uint16_t hostEndpoint, chreMessageFreeFunction *freeCallback) { 33 EventLoop *eventLoop = chre::getCurrentEventLoop(); 34 CHRE_ASSERT(eventLoop); 35 36 Nanoapp *currentApp = eventLoop->getCurrentNanoapp(); 37 CHRE_ASSERT(currentApp); 38 39 bool success = false; 40 if (messageSize > 0 && messageData == nullptr) { 41 LOGW("Rejecting malformed message (null data but non-zero size)"); 42 } else if (messageSize > CHRE_MESSAGE_TO_HOST_MAX_SIZE) { 43 LOGW("Rejecting message of size %zu bytes (max %d)", 44 messageSize, CHRE_MESSAGE_TO_HOST_MAX_SIZE); 45 } else if (hostEndpoint == kHostEndpointUnspecified) { 46 LOGW("Rejecting message to invalid host endpoint"); 47 } else { 48 MessageToHost *msgToHost = mMessagePool.allocate(); 49 50 if (msgToHost == nullptr) { 51 LOGE("Couldn't allocate message to host"); 52 } else { 53 msgToHost->appId = currentApp->getAppId(); 54 msgToHost->message.wrap(static_cast<uint8_t *>(messageData), messageSize); 55 msgToHost->toHostData.hostEndpoint = hostEndpoint; 56 msgToHost->toHostData.messageType = messageType; 57 msgToHost->toHostData.nanoappFreeFunction = freeCallback; 58 59 // Populate a special value to help disambiguate message direction when 60 // debugging 61 msgToHost->toHostData.reserved = kMessageToHostReservedFieldValue; 62 63 success = mHostLink.sendMessage(msgToHost); 64 if (!success) { 65 freeMessageToHost(msgToHost); 66 } 67 } 68 } 69 70 return success; 71 } 72 73 void HostCommsManager::deliverNanoappMessageFromHost( 74 uint64_t appId, uint16_t hostEndpoint, uint32_t messageType, 75 const void *messageData, uint32_t messageSize, EventLoop *targetEventLoop, 76 uint32_t targetInstanceId) { 77 CHRE_ASSERT(targetEventLoop != nullptr); 78 bool success = false; 79 80 MessageFromHost *msgFromHost = mMessagePool.allocate(); 81 if (msgFromHost == nullptr) { 82 LOGE("Couldn't allocate message from host"); 83 } else if (!msgFromHost->message.copy_array( 84 static_cast<const uint8_t *>(messageData), messageSize)) { 85 LOGE("Couldn't allocate %" PRIu32 " bytes for message data from host " 86 "(endpoint 0x%" PRIx16 " type %" PRIu32 ")", messageSize, 87 hostEndpoint, messageType); 88 } else { 89 msgFromHost->appId = appId; 90 msgFromHost->fromHostData.messageType = messageType; 91 msgFromHost->fromHostData.messageSize = static_cast<uint32_t>( 92 messageSize); 93 msgFromHost->fromHostData.message = msgFromHost->message.data(); 94 msgFromHost->fromHostData.hostEndpoint = hostEndpoint; 95 96 success = targetEventLoop->postEvent( 97 CHRE_EVENT_MESSAGE_FROM_HOST, &msgFromHost->fromHostData, 98 freeMessageFromHostCallback, kSystemInstanceId, targetInstanceId); 99 } 100 101 if (!success && msgFromHost != nullptr) { 102 mMessagePool.deallocate(msgFromHost); 103 } 104 } 105 106 void HostCommsManager::sendMessageToNanoappFromHost( 107 uint64_t appId, uint32_t messageType, uint16_t hostEndpoint, 108 const void *messageData, size_t messageSize) { 109 EventLoopManager *eventLoopMgr = EventLoopManagerSingleton::get(); 110 EventLoop *targetEventLoop; 111 uint32_t targetInstanceId; 112 113 if (hostEndpoint == kHostEndpointBroadcast) { 114 LOGE("Received invalid message from host from broadcast endpoint"); 115 } else if (messageSize > ((UINT32_MAX))) { 116 // The current CHRE API uses uint32_t to represent the message size in 117 // struct chreMessageFromHostData. We don't expect to ever need to exceed 118 // this, but the check ensures we're on the up and up. 119 LOGE("Rejecting message of size %zu (too big)", messageSize); 120 } else if (!eventLoopMgr->findNanoappInstanceIdByAppId(appId, 121 &targetInstanceId, 122 &targetEventLoop)) { 123 LOGE("Dropping message; destination app ID 0x%016" PRIx64 " not found", 124 appId); 125 } else { 126 deliverNanoappMessageFromHost(appId, hostEndpoint, messageType, messageData, 127 static_cast<uint32_t>(messageSize), 128 targetEventLoop, targetInstanceId); 129 } 130 } 131 132 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) { 133 // Removing const on message since we own the memory and will deallocate it; 134 // the caller (HostLink) only gets a const pointer 135 auto *msgToHost = const_cast<MessageToHost *>(message); 136 137 // If there's no free callback, we can free the message right away as the 138 // message pool is thread-safe; otherwise, we need to do it from within the 139 // EventLoop context. 140 if (msgToHost->toHostData.nanoappFreeFunction == nullptr) { 141 mMessagePool.deallocate(msgToHost); 142 } else { 143 auto freeMsgCallback = [](uint16_t /*type*/, void *data) { 144 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost( 145 static_cast<MessageToHost *>(data)); 146 }; 147 148 bool eventPosted = EventLoopManagerSingleton::get()->deferCallback( 149 SystemCallbackType::MessageToHostComplete, msgToHost, freeMsgCallback); 150 151 // If this assert/log triggers, we're leaking resources 152 // TODO: should have reserved space in event queue to prevent nanoapps from 153 // negatively impacting system functionality 154 CHRE_ASSERT_LOG(eventPosted, "Couldn't defer callback to clean up message " 155 "to host!"); 156 } 157 } 158 159 void HostCommsManager::freeMessageToHost(MessageToHost *msgToHost) { 160 if (msgToHost->toHostData.nanoappFreeFunction != nullptr) { 161 msgToHost->toHostData.nanoappFreeFunction(msgToHost->message.data(), 162 msgToHost->message.size()); 163 } 164 mMessagePool.deallocate(msgToHost); 165 } 166 167 void HostCommsManager::freeMessageFromHostCallback(uint16_t /*type*/, 168 void *data) { 169 // We pass the chreMessageFromHostData structure to the nanoapp as the event's 170 // data pointer, but we need to return to the enclosing HostMessage pointer. 171 // As long as HostMessage is standard-layout, and fromHostData is the first 172 // field, we can convert between these two pointers via reinterpret_cast. 173 // These static assertions ensure this assumption is held. 174 static_assert(std::is_standard_layout<HostMessage>::value, 175 "HostMessage* is derived from HostMessage::fromHostData*, " 176 "therefore it must be standard layout"); 177 static_assert(offsetof(MessageFromHost, fromHostData) == 0, 178 "fromHostData must be the first field in HostMessage"); 179 180 auto *eventData = static_cast<chreMessageFromHostData *>(data); 181 auto *msgFromHost = reinterpret_cast<MessageFromHost *>(eventData); 182 auto& hostCommsMgr = EventLoopManagerSingleton::get()->getHostCommsManager(); 183 hostCommsMgr.mMessagePool.deallocate(msgFromHost); 184 } 185 186 187 } // namespace chre 188