• 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       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