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 #include "chre/util/macros.h"
25
26 namespace chre {
27
sendMessageToHostFromNanoapp(Nanoapp * nanoapp,void * messageData,size_t messageSize,uint32_t messageType,uint16_t hostEndpoint,uint32_t messagePermissions,chreMessageFreeFunction * freeCallback)28 bool HostCommsManager::sendMessageToHostFromNanoapp(
29 Nanoapp *nanoapp, void *messageData, size_t messageSize,
30 uint32_t messageType, uint16_t hostEndpoint, uint32_t messagePermissions,
31 chreMessageFreeFunction *freeCallback) {
32 bool success = false;
33 if (messageSize > 0 && messageData == nullptr) {
34 LOGW("Rejecting malformed message (null data but non-zero size)");
35 } else if (messageSize > CHRE_MESSAGE_TO_HOST_MAX_SIZE) {
36 LOGW("Rejecting message of size %zu bytes (max %d)", messageSize,
37 CHRE_MESSAGE_TO_HOST_MAX_SIZE);
38 } else if (hostEndpoint == kHostEndpointUnspecified) {
39 LOGW("Rejecting message to invalid host endpoint");
40 } else if (!BITMASK_HAS_VALUE(nanoapp->getAppPermissions(),
41 messagePermissions)) {
42 LOGE("Message perms %" PRIx32 " not subset of napp perms %" PRIx32,
43 messagePermissions, nanoapp->getAppPermissions());
44 } else {
45 MessageToHost *msgToHost = mMessagePool.allocate();
46
47 if (msgToHost == nullptr) {
48 LOG_OOM();
49 } else {
50 msgToHost->appId = nanoapp->getAppId();
51 msgToHost->message.wrap(static_cast<uint8_t *>(messageData), messageSize);
52 msgToHost->toHostData.hostEndpoint = hostEndpoint;
53 msgToHost->toHostData.messageType = messageType;
54 msgToHost->toHostData.messagePermissions = messagePermissions;
55 msgToHost->toHostData.appPermissions = nanoapp->getAppPermissions();
56 msgToHost->toHostData.nanoappFreeFunction = freeCallback;
57
58 // Let the nanoapp know that it woke up the host and record it
59 bool hostWasAwake = EventLoopManagerSingleton::get()
60 ->getEventLoop()
61 .getPowerControlManager()
62 .hostIsAwake();
63
64 bool wokeHost = !hostWasAwake && !mIsNanoappBlamedForWakeup;
65 msgToHost->toHostData.wokeHost = wokeHost;
66
67 success = HostLink::sendMessage(msgToHost);
68 if (!success) {
69 mMessagePool.deallocate(msgToHost);
70 } else if (wokeHost) {
71 // If message successfully sent and host was suspended before sending
72 EventLoopManagerSingleton::get()
73 ->getEventLoop()
74 .handleNanoappWakeupBuckets();
75 mIsNanoappBlamedForWakeup = true;
76 nanoapp->blameHostWakeup();
77 }
78 }
79 }
80
81 return success;
82 }
83
craftNanoappMessageFromHost(uint64_t appId,uint16_t hostEndpoint,uint32_t messageType,const void * messageData,uint32_t messageSize)84 MessageFromHost *HostCommsManager::craftNanoappMessageFromHost(
85 uint64_t appId, uint16_t hostEndpoint, uint32_t messageType,
86 const void *messageData, uint32_t messageSize) {
87 MessageFromHost *msgFromHost = mMessagePool.allocate();
88 if (msgFromHost == nullptr) {
89 LOG_OOM();
90 } else if (!msgFromHost->message.copy_array(
91 static_cast<const uint8_t *>(messageData), messageSize)) {
92 LOGE("Couldn't allocate %" PRIu32
93 " bytes for message data from host "
94 "(endpoint 0x%" PRIx16 " type %" PRIu32 ")",
95 messageSize, hostEndpoint, messageType);
96 mMessagePool.deallocate(msgFromHost);
97 msgFromHost = nullptr;
98 } else {
99 msgFromHost->appId = appId;
100 msgFromHost->fromHostData.messageType = messageType;
101 msgFromHost->fromHostData.messageSize = messageSize;
102 msgFromHost->fromHostData.message = msgFromHost->message.data();
103 msgFromHost->fromHostData.hostEndpoint = hostEndpoint;
104 }
105
106 return msgFromHost;
107 }
108
deliverNanoappMessageFromHost(MessageFromHost * craftedMessage)109 bool HostCommsManager::deliverNanoappMessageFromHost(
110 MessageFromHost *craftedMessage) {
111 const EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
112 uint16_t targetInstanceId;
113 bool nanoappFound = false;
114
115 CHRE_ASSERT_LOG(craftedMessage != nullptr,
116 "Cannot deliver NULL pointer nanoapp message from host");
117
118 if (eventLoop.findNanoappInstanceIdByAppId(craftedMessage->appId,
119 &targetInstanceId)) {
120 nanoappFound = true;
121 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
122 CHRE_EVENT_MESSAGE_FROM_HOST, &craftedMessage->fromHostData,
123 freeMessageFromHostCallback, targetInstanceId);
124 }
125
126 return nanoappFound;
127 }
128
sendMessageToNanoappFromHost(uint64_t appId,uint32_t messageType,uint16_t hostEndpoint,const void * messageData,size_t messageSize)129 void HostCommsManager::sendMessageToNanoappFromHost(uint64_t appId,
130 uint32_t messageType,
131 uint16_t hostEndpoint,
132 const void *messageData,
133 size_t messageSize) {
134 if (hostEndpoint == kHostEndpointBroadcast) {
135 LOGE("Received invalid message from host from broadcast endpoint");
136 } else if (messageSize > ((UINT32_MAX))) {
137 // The current CHRE API uses uint32_t to represent the message size in
138 // struct chreMessageFromHostData. We don't expect to ever need to exceed
139 // this, but the check ensures we're on the up and up.
140 LOGE("Rejecting message of size %zu (too big)", messageSize);
141 } else {
142 MessageFromHost *craftedMessage = craftNanoappMessageFromHost(
143 appId, hostEndpoint, messageType, messageData,
144 static_cast<uint32_t>(messageSize));
145 if (craftedMessage == nullptr) {
146 LOGE("Out of memory - rejecting message to app ID 0x%016" PRIx64
147 "(size %zu)",
148 appId, messageSize);
149 } else if (!deliverNanoappMessageFromHost(craftedMessage)) {
150 LOGV("Deferring message; destination app ID 0x%016" PRIx64
151 " not found at this time",
152 appId);
153
154 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
155 EventLoopManagerSingleton::get()
156 ->getHostCommsManager()
157 .sendDeferredMessageToNanoappFromHost(
158 static_cast<MessageFromHost *>(data));
159 };
160 if (!EventLoopManagerSingleton::get()->deferCallback(
161 SystemCallbackType::DeferredMessageToNanoappFromHost,
162 craftedMessage, callback)) {
163 mMessagePool.deallocate(craftedMessage);
164 }
165 }
166 }
167 }
168
sendDeferredMessageToNanoappFromHost(MessageFromHost * craftedMessage)169 void HostCommsManager::sendDeferredMessageToNanoappFromHost(
170 MessageFromHost *craftedMessage) {
171 CHRE_ASSERT_LOG(craftedMessage != nullptr,
172 "Deferred message from host is a NULL pointer");
173
174 if (!deliverNanoappMessageFromHost(craftedMessage)) {
175 LOGE("Dropping deferred message; destination app ID 0x%016" PRIx64
176 " still not found",
177 craftedMessage->appId);
178 mMessagePool.deallocate(craftedMessage);
179 } else {
180 LOGD("Deferred message to app ID 0x%016" PRIx64 " delivered",
181 craftedMessage->appId);
182 }
183 }
184
resetBlameForNanoappHostWakeup()185 void HostCommsManager::resetBlameForNanoappHostWakeup() {
186 mIsNanoappBlamedForWakeup = false;
187 }
188
onMessageToHostComplete(const MessageToHost * message)189 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) {
190 // Removing const on message since we own the memory and will deallocate it;
191 // the caller (HostLink) only gets a const pointer
192 auto *msgToHost = const_cast<MessageToHost *>(message);
193
194 // If there's no free callback, we can free the message right away as the
195 // message pool is thread-safe; otherwise, we need to do it from within the
196 // EventLoop context.
197 if (msgToHost->toHostData.nanoappFreeFunction == nullptr) {
198 mMessagePool.deallocate(msgToHost);
199 } else {
200 auto freeMsgCallback = [](uint16_t /*type*/, void *data,
201 void * /*extraData*/) {
202 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
203 static_cast<MessageToHost *>(data));
204 };
205
206 if (!EventLoopManagerSingleton::get()->deferCallback(
207 SystemCallbackType::MessageToHostComplete, msgToHost,
208 freeMsgCallback)) {
209 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
210 static_cast<MessageToHost *>(msgToHost));
211 }
212 }
213 }
214
freeMessageToHost(MessageToHost * msgToHost)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
freeMessageFromHostCallback(uint16_t,void * data)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