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 
25 namespace chre {
26 
27 constexpr uint32_t kMessageToHostReservedFieldValue = UINT32_MAX;
28 
29 void HostCommsManager::flushMessagesSentByNanoapp(uint64_t appId) {
30   mHostLink.flushMessagesSentByNanoapp(appId);
31 }
32 
33 void HostCommsManager::sendLogMessage(const char *logMessage,
34                                       size_t logMessageSize) {
35   mHostLink.sendLogMessage(logMessage, logMessageSize);
36 }
37 
38 bool HostCommsManager::sendMessageToHostFromNanoapp(
39     Nanoapp *nanoapp, void *messageData, size_t messageSize,
40     uint32_t messageType, uint16_t hostEndpoint,
41     chreMessageFreeFunction *freeCallback) {
42   bool success = false;
43   if (messageSize > 0 && messageData == nullptr) {
44     LOGW("Rejecting malformed message (null data but non-zero size)");
45   } else if (messageSize > CHRE_MESSAGE_TO_HOST_MAX_SIZE) {
46     LOGW("Rejecting message of size %zu bytes (max %d)", messageSize,
47          CHRE_MESSAGE_TO_HOST_MAX_SIZE);
48   } else if (hostEndpoint == kHostEndpointUnspecified) {
49     LOGW("Rejecting message to invalid host endpoint");
50   } else {
51     MessageToHost *msgToHost = mMessagePool.allocate();
52 
53     if (msgToHost == nullptr) {
54       LOG_OOM();
55     } else {
56       msgToHost->appId = nanoapp->getAppId();
57       msgToHost->message.wrap(static_cast<uint8_t *>(messageData), messageSize);
58       msgToHost->toHostData.hostEndpoint = hostEndpoint;
59       msgToHost->toHostData.messageType = messageType;
60       msgToHost->toHostData.nanoappFreeFunction = freeCallback;
61 
62       // Populate a special value to help disambiguate message direction when
63       // debugging
64       msgToHost->toHostData.reserved = kMessageToHostReservedFieldValue;
65 
66       // Let the nanoapp know that it woke up the host and record it
67       bool hostWasAwake = EventLoopManagerSingleton::get()
68                               ->getEventLoop()
69                               .getPowerControlManager()
70                               .hostIsAwake();
71 
72       success = mHostLink.sendMessage(msgToHost);
73       if (!success) {
74         mMessagePool.deallocate(msgToHost);
75       } else if (!hostWasAwake && !mIsNanoappBlamedForWakeup) {
76         // If message successfully sent and host was suspended before sending
77         EventLoopManagerSingleton::get()
78             ->getEventLoop()
79             .handleNanoappWakeupBuckets();
80         mIsNanoappBlamedForWakeup = true;
81         nanoapp->blameHostWakeup();
82       }
83     }
84   }
85 
86   return success;
87 }
88 
89 MessageFromHost *HostCommsManager::craftNanoappMessageFromHost(
90     uint64_t appId, uint16_t hostEndpoint, uint32_t messageType,
91     const void *messageData, uint32_t messageSize) {
92   MessageFromHost *msgFromHost = mMessagePool.allocate();
93   if (msgFromHost == nullptr) {
94     LOG_OOM();
95   } else if (!msgFromHost->message.copy_array(
96                  static_cast<const uint8_t *>(messageData), messageSize)) {
97     LOGE("Couldn't allocate %" PRIu32
98          " bytes for message data from host "
99          "(endpoint 0x%" PRIx16 " type %" PRIu32 ")",
100          messageSize, hostEndpoint, messageType);
101     mMessagePool.deallocate(msgFromHost);
102     msgFromHost = nullptr;
103   } else {
104     msgFromHost->appId = appId;
105     msgFromHost->fromHostData.messageType = messageType;
106     msgFromHost->fromHostData.messageSize = messageSize;
107     msgFromHost->fromHostData.message = msgFromHost->message.data();
108     msgFromHost->fromHostData.hostEndpoint = hostEndpoint;
109   }
110 
111   return msgFromHost;
112 }
113 
114 bool HostCommsManager::deliverNanoappMessageFromHost(
115     MessageFromHost *craftedMessage) {
116   const EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
117   uint32_t targetInstanceId;
118   bool success = false;
119 
120   CHRE_ASSERT_LOG(craftedMessage != nullptr,
121                   "Cannot deliver NULL pointer nanoapp message from host");
122 
123   if (eventLoop.findNanoappInstanceIdByAppId(craftedMessage->appId,
124                                              &targetInstanceId)) {
125     success = true;
126     if (!EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
127             CHRE_EVENT_MESSAGE_FROM_HOST, &craftedMessage->fromHostData,
128             freeMessageFromHostCallback, targetInstanceId)) {
129       mMessagePool.deallocate(craftedMessage);
130     }
131   }
132 
133   return success;
134 }
135 
136 void HostCommsManager::sendMessageToNanoappFromHost(uint64_t appId,
137                                                     uint32_t messageType,
138                                                     uint16_t hostEndpoint,
139                                                     const void *messageData,
140                                                     size_t messageSize) {
141   if (hostEndpoint == kHostEndpointBroadcast) {
142     LOGE("Received invalid message from host from broadcast endpoint");
143   } else if (messageSize > ((UINT32_MAX))) {
144     // The current CHRE API uses uint32_t to represent the message size in
145     // struct chreMessageFromHostData. We don't expect to ever need to exceed
146     // this, but the check ensures we're on the up and up.
147     LOGE("Rejecting message of size %zu (too big)", messageSize);
148   } else {
149     MessageFromHost *craftedMessage = craftNanoappMessageFromHost(
150         appId, hostEndpoint, messageType, messageData,
151         static_cast<uint32_t>(messageSize));
152     if (craftedMessage == nullptr) {
153       LOGE("Out of memory - rejecting message to app ID 0x%016" PRIx64
154            "(size %zu)",
155            appId, messageSize);
156     } else if (!deliverNanoappMessageFromHost(craftedMessage)) {
157       LOGD("Deferring message; destination app ID 0x%016" PRIx64
158            " not found at this time",
159            appId);
160 
161       auto deferredMessageCallback = [](uint16_t /*type*/, void *data) {
162         EventLoopManagerSingleton::get()
163             ->getHostCommsManager()
164             .sendDeferredMessageToNanoappFromHost(
165                 static_cast<MessageFromHost *>(data));
166       };
167       EventLoopManagerSingleton::get()->deferCallback(
168           SystemCallbackType::DeferredMessageToNanoappFromHost, craftedMessage,
169           deferredMessageCallback);
170     }
171   }
172 }
173 
174 void HostCommsManager::sendDeferredMessageToNanoappFromHost(
175     MessageFromHost *craftedMessage) {
176   CHRE_ASSERT_LOG(craftedMessage != nullptr,
177                   "Deferred message from host is a NULL pointer");
178 
179   if (!deliverNanoappMessageFromHost(craftedMessage)) {
180     LOGE("Dropping deferred message; destination app ID 0x%016" PRIx64
181          " still not found",
182          craftedMessage->appId);
183     mMessagePool.deallocate(craftedMessage);
184   } else {
185     LOGD("Deferred message to app ID 0x%016" PRIx64 " delivered",
186          craftedMessage->appId);
187   }
188 }
189 
190 void HostCommsManager::resetBlameForNanoappHostWakeup() {
191   mIsNanoappBlamedForWakeup = false;
192 }
193 
194 void HostCommsManager::onMessageToHostComplete(const MessageToHost *message) {
195   // Removing const on message since we own the memory and will deallocate it;
196   // the caller (HostLink) only gets a const pointer
197   auto *msgToHost = const_cast<MessageToHost *>(message);
198 
199   // If there's no free callback, we can free the message right away as the
200   // message pool is thread-safe; otherwise, we need to do it from within the
201   // EventLoop context.
202   if (msgToHost->toHostData.nanoappFreeFunction == nullptr) {
203     mMessagePool.deallocate(msgToHost);
204   } else {
205     auto freeMsgCallback = [](uint16_t /*type*/, void *data) {
206       EventLoopManagerSingleton::get()->getHostCommsManager().freeMessageToHost(
207           static_cast<MessageToHost *>(data));
208     };
209 
210     EventLoopManagerSingleton::get()->deferCallback(
211         SystemCallbackType::MessageToHostComplete, msgToHost, freeMsgCallback);
212   }
213 }
214 
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 
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