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