• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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