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 EventLoopManagerSingleton::get()->deferCallback(
161 SystemCallbackType::DeferredMessageToNanoappFromHost, craftedMessage,
162 callback);
163 }
164 }
165 }
166
sendDeferredMessageToNanoappFromHost(MessageFromHost * craftedMessage)167 void HostCommsManager::sendDeferredMessageToNanoappFromHost(
168 MessageFromHost *craftedMessage) {
169 CHRE_ASSERT_LOG(craftedMessage != nullptr,
170 "Deferred message from host is a NULL pointer");
171
172 if (!deliverNanoappMessageFromHost(craftedMessage)) {
173 LOGE("Dropping deferred message; destination app ID 0x%016" PRIx64
174 " still not found",
175 craftedMessage->appId);
176 mMessagePool.deallocate(craftedMessage);
177 } else {
178 LOGD("Deferred message to app ID 0x%016" PRIx64 " delivered",
179 craftedMessage->appId);
180 }
181 }
182
resetBlameForNanoappHostWakeup()183 void HostCommsManager::resetBlameForNanoappHostWakeup() {
184 mIsNanoappBlamedForWakeup = false;
185 }
186
onMessageToHostComplete(const MessageToHost * message)187 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) {
188 // Removing const on message since we own the memory and will deallocate it;
189 // the caller (HostLink) only gets a const pointer
190 auto *msgToHost = const_cast<MessageToHost *>(message);
191
192 // If there's no free callback, we can free the message right away as the
193 // message pool is thread-safe; otherwise, we need to do it from within the
194 // EventLoop context.
195 if (msgToHost->toHostData.nanoappFreeFunction == nullptr) {
196 mMessagePool.deallocate(msgToHost);
197 } else {
198 auto freeMsgCallback = [](uint16_t /*type*/, void *data,
199 void * /*extraData*/) {
200 EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
201 static_cast<MessageToHost *>(data));
202 };
203
204 EventLoopManagerSingleton::get()->deferCallback(
205 SystemCallbackType::MessageToHostComplete, msgToHost, freeMsgCallback);
206 }
207 }
208
freeMessageToHost(MessageToHost * msgToHost)209 void HostCommsManager::freeMessageToHost(MessageToHost *msgToHost) {
210 if (msgToHost->toHostData.nanoappFreeFunction != nullptr) {
211 EventLoopManagerSingleton::get()->getEventLoop().invokeMessageFreeFunction(
212 msgToHost->appId, msgToHost->toHostData.nanoappFreeFunction,
213 msgToHost->message.data(), msgToHost->message.size());
214 }
215 mMessagePool.deallocate(msgToHost);
216 }
217
freeMessageFromHostCallback(uint16_t,void * data)218 void HostCommsManager::freeMessageFromHostCallback(uint16_t /*type*/,
219 void *data) {
220 // We pass the chreMessageFromHostData structure to the nanoapp as the event's
221 // data pointer, but we need to return to the enclosing HostMessage pointer.
222 // As long as HostMessage is standard-layout, and fromHostData is the first
223 // field, we can convert between these two pointers via reinterpret_cast.
224 // These static assertions ensure this assumption is held.
225 static_assert(std::is_standard_layout<HostMessage>::value,
226 "HostMessage* is derived from HostMessage::fromHostData*, "
227 "therefore it must be standard layout");
228 static_assert(offsetof(MessageFromHost, fromHostData) == 0,
229 "fromHostData must be the first field in HostMessage");
230
231 auto *eventData = static_cast<chreMessageFromHostData *>(data);
232 auto *msgFromHost = reinterpret_cast<MessageFromHost *>(eventData);
233 auto &hostCommsMgr = EventLoopManagerSingleton::get()->getHostCommsManager();
234 hostCommsMgr.mMessagePool.deallocate(msgFromHost);
235 }
236
237 } // namespace chre
238