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