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 success = HostLink::sendMessage(msgToHost);
65 if (!success) {
66 mMessagePool.deallocate(msgToHost);
67 } else if (!hostWasAwake && !mIsNanoappBlamedForWakeup) {
68 // If message successfully sent and host was suspended before sending
69 EventLoopManagerSingleton::get()
70 ->getEventLoop()
71 .handleNanoappWakeupBuckets();
72 mIsNanoappBlamedForWakeup = true;
73 nanoapp->blameHostWakeup();
74 }
75 }
76 }
77
78 return success;
79 }
80
craftNanoappMessageFromHost(uint64_t appId,uint16_t hostEndpoint,uint32_t messageType,const void * messageData,uint32_t messageSize)81 MessageFromHost *HostCommsManager::craftNanoappMessageFromHost(
82 uint64_t appId, uint16_t hostEndpoint, uint32_t messageType,
83 const void *messageData, uint32_t messageSize) {
84 MessageFromHost *msgFromHost = mMessagePool.allocate();
85 if (msgFromHost == nullptr) {
86 LOG_OOM();
87 } else if (!msgFromHost->message.copy_array(
88 static_cast<const uint8_t *>(messageData), messageSize)) {
89 LOGE("Couldn't allocate %" PRIu32
90 " bytes for message data from host "
91 "(endpoint 0x%" PRIx16 " type %" PRIu32 ")",
92 messageSize, hostEndpoint, messageType);
93 mMessagePool.deallocate(msgFromHost);
94 msgFromHost = nullptr;
95 } else {
96 msgFromHost->appId = appId;
97 msgFromHost->fromHostData.messageType = messageType;
98 msgFromHost->fromHostData.messageSize = messageSize;
99 msgFromHost->fromHostData.message = msgFromHost->message.data();
100 msgFromHost->fromHostData.hostEndpoint = hostEndpoint;
101 }
102
103 return msgFromHost;
104 }
105
deliverNanoappMessageFromHost(MessageFromHost * craftedMessage)106 bool HostCommsManager::deliverNanoappMessageFromHost(
107 MessageFromHost *craftedMessage) {
108 const EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
109 uint32_t targetInstanceId;
110 bool nanoappFound = false;
111
112 CHRE_ASSERT_LOG(craftedMessage != nullptr,
113 "Cannot deliver NULL pointer nanoapp message from host");
114
115 if (eventLoop.findNanoappInstanceIdByAppId(craftedMessage->appId,
116 &targetInstanceId)) {
117 nanoappFound = true;
118 EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
119 CHRE_EVENT_MESSAGE_FROM_HOST, &craftedMessage->fromHostData,
120 freeMessageFromHostCallback, targetInstanceId);
121 }
122
123 return nanoappFound;
124 }
125
sendMessageToNanoappFromHost(uint64_t appId,uint32_t messageType,uint16_t hostEndpoint,const void * messageData,size_t messageSize)126 void HostCommsManager::sendMessageToNanoappFromHost(uint64_t appId,
127 uint32_t messageType,
128 uint16_t hostEndpoint,
129 const void *messageData,
130 size_t messageSize) {
131 if (hostEndpoint == kHostEndpointBroadcast) {
132 LOGE("Received invalid message from host from broadcast endpoint");
133 } else if (messageSize > ((UINT32_MAX))) {
134 // The current CHRE API uses uint32_t to represent the message size in
135 // struct chreMessageFromHostData. We don't expect to ever need to exceed
136 // this, but the check ensures we're on the up and up.
137 LOGE("Rejecting message of size %zu (too big)", messageSize);
138 } else {
139 MessageFromHost *craftedMessage = craftNanoappMessageFromHost(
140 appId, hostEndpoint, messageType, messageData,
141 static_cast<uint32_t>(messageSize));
142 if (craftedMessage == nullptr) {
143 LOGE("Out of memory - rejecting message to app ID 0x%016" PRIx64
144 "(size %zu)",
145 appId, messageSize);
146 } else if (!deliverNanoappMessageFromHost(craftedMessage)) {
147 LOGV("Deferring message; destination app ID 0x%016" PRIx64
148 " not found at this time",
149 appId);
150
151 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
152 EventLoopManagerSingleton::get()
153 ->getHostCommsManager()
154 .sendDeferredMessageToNanoappFromHost(
155 static_cast<MessageFromHost *>(data));
156 };
157 EventLoopManagerSingleton::get()->deferCallback(
158 SystemCallbackType::DeferredMessageToNanoappFromHost, craftedMessage,
159 callback);
160 }
161 }
162 }
163
sendDeferredMessageToNanoappFromHost(MessageFromHost * craftedMessage)164 void HostCommsManager::sendDeferredMessageToNanoappFromHost(
165 MessageFromHost *craftedMessage) {
166 CHRE_ASSERT_LOG(craftedMessage != nullptr,
167 "Deferred message from host is a NULL pointer");
168
169 if (!deliverNanoappMessageFromHost(craftedMessage)) {
170 LOGE("Dropping deferred message; destination app ID 0x%016" PRIx64
171 " still not found",
172 craftedMessage->appId);
173 mMessagePool.deallocate(craftedMessage);
174 } else {
175 LOGD("Deferred message to app ID 0x%016" PRIx64 " delivered",
176 craftedMessage->appId);
177 }
178 }
179
resetBlameForNanoappHostWakeup()180 void HostCommsManager::resetBlameForNanoappHostWakeup() {
181 mIsNanoappBlamedForWakeup = false;
182 }
183
onMessageToHostComplete(const MessageToHost * message)184 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) {
185 // Removing const on message since we own the memory and will deallocate it;
186 // the caller (HostLink) only gets a const pointer
187 auto *msgToHost = const_cast<MessageToHost *>(message);
188
189 // If there's no free callback, we can free the message right away as the
190 // message pool is thread-safe; otherwise, we need to do it from within the
191 // EventLoop context.
192 if (msgToHost->toHostData.nanoappFreeFunction == nullptr) {
193 mMessagePool.deallocate(msgToHost);
194 } else {
195 auto freeMsgCallback = [](uint16_t /*type*/, void *data,
196 void * /*extraData*/) {
197 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
198 static_cast<MessageToHost *>(data));
199 };
200
201 EventLoopManagerSingleton::get()->deferCallback(
202 SystemCallbackType::MessageToHostComplete, msgToHost, freeMsgCallback);
203 }
204 }
205
freeMessageToHost(MessageToHost * msgToHost)206 void HostCommsManager::freeMessageToHost(MessageToHost *msgToHost) {
207 if (msgToHost->toHostData.nanoappFreeFunction != nullptr) {
208 EventLoopManagerSingleton::get()->getEventLoop().invokeMessageFreeFunction(
209 msgToHost->appId, msgToHost->toHostData.nanoappFreeFunction,
210 msgToHost->message.data(), msgToHost->message.size());
211 }
212 mMessagePool.deallocate(msgToHost);
213 }
214
freeMessageFromHostCallback(uint16_t,void * data)215 void HostCommsManager::freeMessageFromHostCallback(uint16_t /*type*/,
216 void *data) {
217 // We pass the chreMessageFromHostData structure to the nanoapp as the event's
218 // data pointer, but we need to return to the enclosing HostMessage pointer.
219 // As long as HostMessage is standard-layout, and fromHostData is the first
220 // field, we can convert between these two pointers via reinterpret_cast.
221 // These static assertions ensure this assumption is held.
222 static_assert(std::is_standard_layout<HostMessage>::value,
223 "HostMessage* is derived from HostMessage::fromHostData*, "
224 "therefore it must be standard layout");
225 static_assert(offsetof(MessageFromHost, fromHostData) == 0,
226 "fromHostData must be the first field in HostMessage");
227
228 auto *eventData = static_cast<chreMessageFromHostData *>(data);
229 auto *msgFromHost = reinterpret_cast<MessageFromHost *>(eventData);
230 auto &hostCommsMgr = EventLoopManagerSingleton::get()->getHostCommsManager();
231 hostCommsMgr.mMessagePool.deallocate(msgFromHost);
232 }
233
234 } // namespace chre
235