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 #ifndef FARF_MEDIUM
18 #define FARF_MEDIUM 1
19 #endif
20
21 #include "HAP_farf.h"
22 #include "timer.h"
23
24 #include "chre/core/event_loop_manager.h"
25 #include "chre/core/host_comms_manager.h"
26 #include "chre/core/settings.h"
27 #include "chre/platform/fatal_error.h"
28 #include "chre/platform/log.h"
29 #include "chre/platform/memory.h"
30 #include "chre/platform/shared/host_protocol_chre.h"
31 #include "chre/platform/shared/nanoapp_load_manager.h"
32 #ifdef CHRE_USE_BUFFERED_LOGGING
33 #include "chre/platform/shared/log_buffer_manager.h"
34 #endif
35 #include "chre/platform/slpi/fastrpc.h"
36 #include "chre/platform/slpi/power_control_util.h"
37 #include "chre/platform/system_time.h"
38 #include "chre/platform/system_timer.h"
39 #include "chre/util/fixed_size_blocking_queue.h"
40 #include "chre/util/flatbuffers/helpers.h"
41 #include "chre/util/macros.h"
42 #include "chre/util/nested_data_ptr.h"
43 #include "chre/util/unique_ptr.h"
44 #include "chre_api/chre/version.h"
45
46 #include <inttypes.h>
47 #include <limits.h>
48
49 namespace chre {
50
51 namespace {
52
53 constexpr size_t kOutboundQueueSize = 32;
54
55 //! The last time a time sync request message has been sent.
56 //! TODO: Make this a member of HostLinkBase
57 Nanoseconds gLastTimeSyncRequestNanos(0);
58
59 struct NanoappListData {
60 ChreFlatBufferBuilder *builder;
61 DynamicVector<NanoappListEntryOffset> nanoappEntries;
62 uint16_t hostClientId;
63 };
64
65 enum class PendingMessageType {
66 Shutdown,
67 NanoappMessageToHost,
68 HubInfoResponse,
69 NanoappListResponse,
70 LoadNanoappResponse,
71 UnloadNanoappResponse,
72 DebugDumpData,
73 DebugDumpResponse,
74 TimeSyncRequest,
75 LowPowerMicAccessRequest,
76 LowPowerMicAccessRelease,
77 EncodedLogMessage,
78 SelfTestResponse,
79 MetricLog,
80 NanConfigurationRequest,
81 };
82
83 struct PendingMessage {
PendingMessagechre::__anonaa635afe0111::PendingMessage84 PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
85 type = msgType;
86 data.hostClientId = hostClientId;
87 }
88
PendingMessagechre::__anonaa635afe0111::PendingMessage89 PendingMessage(PendingMessageType msgType,
90 const MessageToHost *msgToHost = nullptr) {
91 type = msgType;
92 data.msgToHost = msgToHost;
93 }
94
PendingMessagechre::__anonaa635afe0111::PendingMessage95 PendingMessage(PendingMessageType msgType, ChreFlatBufferBuilder *builder) {
96 type = msgType;
97 data.builder = builder;
98 }
99
100 PendingMessageType type;
101 union {
102 const MessageToHost *msgToHost;
103 uint16_t hostClientId;
104 ChreFlatBufferBuilder *builder;
105 } data;
106 };
107
108 struct UnloadNanoappCallbackData {
109 uint64_t appId;
110 uint32_t transactionId;
111 uint16_t hostClientId;
112 bool allowSystemNanoappUnload;
113 };
114
115 /**
116 * @see buildAndEnqueueMessage()
117 */
118 typedef void(MessageBuilderFunction)(ChreFlatBufferBuilder &builder,
119 void *cookie);
120
121 FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize> gOutboundQueue;
122
copyToHostBuffer(const ChreFlatBufferBuilder & builder,unsigned char * buffer,size_t bufferSize,unsigned int * messageLen)123 int copyToHostBuffer(const ChreFlatBufferBuilder &builder,
124 unsigned char *buffer, size_t bufferSize,
125 unsigned int *messageLen) {
126 uint8_t *data = builder.GetBufferPointer();
127 size_t size = builder.GetSize();
128 int result;
129
130 if (size > bufferSize) {
131 LOGE("Encoded structure size %zu too big for host buffer %zu; dropping",
132 size, bufferSize);
133 result = CHRE_FASTRPC_ERROR;
134 } else {
135 memcpy(buffer, data, size);
136 *messageLen = size;
137 result = CHRE_FASTRPC_SUCCESS;
138 }
139
140 return result;
141 }
142
143 /**
144 * Wrapper function to enqueue a message on the outbound message queue. All
145 * outgoing message to the host must be called through this function.
146 *
147 * @param message The message to send to host.
148 *
149 * @return true if the message was successfully added to the queue.
150 */
enqueueMessage(PendingMessage message)151 bool enqueueMessage(PendingMessage message) {
152 // Vote for big image temporarily when waking up the main thread waiting for
153 // the message
154 bool voteSuccess = slpiForceBigImage();
155 bool success = gOutboundQueue.push(message);
156
157 // Remove the vote only if we successfully made a big image transition
158 if (voteSuccess) {
159 slpiRemoveBigImageVote();
160 }
161
162 return success;
163 }
164
165 /**
166 * Helper function that takes care of the boilerplate for allocating a
167 * ChreFlatBufferBuilder on the heap and adding it to the outbound message
168 * queue.
169 *
170 * @param msgType Identifies the message while in the outboud queue
171 * @param initialBufferSize Number of bytes to reserve when first allocating the
172 * ChreFlatBufferBuilder
173 * @param buildMsgFunc Synchronous callback used to encode the FlatBuffer
174 * message. Will not be invoked if allocation fails.
175 * @param cookie Opaque pointer that will be passed through to buildMsgFunc
176 *
177 * @return true if the message was successfully added to the queue
178 */
buildAndEnqueueMessage(PendingMessageType msgType,size_t initialBufferSize,MessageBuilderFunction * msgBuilder,void * cookie)179 bool buildAndEnqueueMessage(PendingMessageType msgType,
180 size_t initialBufferSize,
181 MessageBuilderFunction *msgBuilder, void *cookie) {
182 bool pushed = false;
183
184 auto builder = MakeUnique<ChreFlatBufferBuilder>(initialBufferSize);
185 if (builder.isNull()) {
186 LOGE("Couldn't allocate memory for message type %d",
187 static_cast<int>(msgType));
188 } else {
189 msgBuilder(*builder, cookie);
190
191 // TODO: if this fails, ideally we should block for some timeout until
192 // there's space in the queue
193 if (!enqueueMessage(PendingMessage(msgType, builder.get()))) {
194 LOGE("Couldn't push message type %d to outbound queue",
195 static_cast<int>(msgType));
196 } else {
197 builder.release();
198 pushed = true;
199 }
200 }
201
202 return pushed;
203 }
204
205 /**
206 * FlatBuffer message builder callback used with handleNanoappListRequest()
207 */
buildNanoappListResponse(ChreFlatBufferBuilder & builder,void * cookie)208 void buildNanoappListResponse(ChreFlatBufferBuilder &builder, void *cookie) {
209 auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) {
210 auto *cbData = static_cast<NanoappListData *>(data);
211 HostProtocolChre::addNanoappListEntry(
212 *(cbData->builder), cbData->nanoappEntries, nanoapp->getAppId(),
213 nanoapp->getAppVersion(), true /*enabled*/, nanoapp->isSystemNanoapp(),
214 nanoapp->getAppPermissions(), nanoapp->getRpcServices());
215 };
216
217 // Add a NanoappListEntry to the FlatBuffer for each nanoapp
218 auto *cbData = static_cast<NanoappListData *>(cookie);
219 cbData->builder = &builder;
220 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
221 eventLoop.forEachNanoapp(nanoappAdderCallback, cbData);
222 HostProtocolChre::finishNanoappListResponse(builder, cbData->nanoappEntries,
223 cbData->hostClientId);
224 }
225
handleUnloadNanoappCallback(SystemCallbackType,UniquePtr<UnloadNanoappCallbackData> && data)226 void handleUnloadNanoappCallback(SystemCallbackType /*type*/,
227 UniquePtr<UnloadNanoappCallbackData> &&data) {
228 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
229 auto *cbData = static_cast<UnloadNanoappCallbackData *>(cookie);
230
231 bool success = false;
232 uint16_t instanceId;
233 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
234 if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) {
235 LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId);
236 } else {
237 success =
238 eventLoop.unloadNanoapp(instanceId, cbData->allowSystemNanoappUnload);
239 }
240
241 HostProtocolChre::encodeUnloadNanoappResponse(
242 builder, cbData->hostClientId, cbData->transactionId, success);
243 };
244
245 constexpr size_t kInitialBufferSize = 52;
246 buildAndEnqueueMessage(PendingMessageType::UnloadNanoappResponse,
247 kInitialBufferSize, msgBuilder, data.get());
248 }
249
generateMessageToHost(const MessageToHost * msgToHost,unsigned char * buffer,size_t bufferSize,unsigned int * messageLen)250 int generateMessageToHost(const MessageToHost *msgToHost, unsigned char *buffer,
251 size_t bufferSize, unsigned int *messageLen) {
252 // TODO: ideally we'd construct our flatbuffer directly in the
253 // host-supplied buffer
254 constexpr size_t kFixedSizePortion = 88;
255 ChreFlatBufferBuilder builder(msgToHost->message.size() + kFixedSizePortion);
256 HostProtocolChre::encodeNanoappMessage(
257 builder, msgToHost->appId, msgToHost->toHostData.messageType,
258 msgToHost->toHostData.hostEndpoint, msgToHost->message.data(),
259 msgToHost->message.size(), msgToHost->toHostData.appPermissions,
260 msgToHost->toHostData.messagePermissions, msgToHost->toHostData.wokeHost);
261
262 int result = copyToHostBuffer(builder, buffer, bufferSize, messageLen);
263
264 auto &hostCommsManager =
265 EventLoopManagerSingleton::get()->getHostCommsManager();
266 hostCommsManager.onMessageToHostComplete(msgToHost);
267
268 return result;
269 }
270
generateHubInfoResponse(uint16_t hostClientId,unsigned char * buffer,size_t bufferSize,unsigned int * messageLen)271 int generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer,
272 size_t bufferSize, unsigned int *messageLen) {
273 constexpr size_t kInitialBufferSize = 192;
274
275 constexpr char kHubName[] = "CHRE on SLPI";
276 constexpr char kVendor[] = "Google";
277 constexpr char kToolchain[] =
278 "Hexagon Tools 8.x (clang " STRINGIFY(__clang_major__) "." STRINGIFY(
279 __clang_minor__) "." STRINGIFY(__clang_patchlevel__) ")";
280 constexpr uint32_t kLegacyPlatformVersion = 0;
281 constexpr uint32_t kLegacyToolchainVersion =
282 ((__clang_major__ & 0xFF) << 24) | ((__clang_minor__ & 0xFF) << 16) |
283 (__clang_patchlevel__ & 0xFFFF);
284 constexpr float kPeakMips = 350;
285 constexpr float kStoppedPower = 0;
286 constexpr float kSleepPower = 1;
287 constexpr float kPeakPower = 15;
288
289 // Note that this may execute prior to EventLoopManager::lateInit() completing
290 ChreFlatBufferBuilder builder(kInitialBufferSize);
291 HostProtocolChre::encodeHubInfoResponse(
292 builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
293 kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
294 kPeakPower, chreGetMessageToHostMaxSize(), chreGetPlatformId(),
295 chreGetVersion(), hostClientId, /* supportsReliableMessage= */ false);
296
297 return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
298 }
299
generateMessageFromBuilder(ChreFlatBufferBuilder * builder,unsigned char * buffer,size_t bufferSize,unsigned int * messageLen,bool isEncodedLogMessage)300 int generateMessageFromBuilder(ChreFlatBufferBuilder *builder,
301 unsigned char *buffer, size_t bufferSize,
302 unsigned int *messageLen,
303 bool isEncodedLogMessage) {
304 CHRE_ASSERT(builder != nullptr);
305 int result = copyToHostBuffer(*builder, buffer, bufferSize, messageLen);
306
307 #ifdef CHRE_USE_BUFFERED_LOGGING
308 if (isEncodedLogMessage && LogBufferManagerSingleton::isInitialized()) {
309 LogBufferManagerSingleton::get()->onLogsSentToHost();
310 }
311 #else
312 UNUSED_VAR(isEncodedLogMessage);
313 #endif
314
315 builder->~ChreFlatBufferBuilder();
316 memoryFree(builder);
317 return result;
318 }
319
sendDebugDumpData(uint16_t hostClientId,const char * debugStr,size_t debugStrSize)320 void sendDebugDumpData(uint16_t hostClientId, const char *debugStr,
321 size_t debugStrSize) {
322 struct DebugDumpMessageData {
323 uint16_t hostClientId;
324 const char *debugStr;
325 size_t debugStrSize;
326 };
327
328 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
329 const auto *data = static_cast<const DebugDumpMessageData *>(cookie);
330 HostProtocolChre::encodeDebugDumpData(builder, data->hostClientId,
331 data->debugStr, data->debugStrSize);
332 };
333
334 constexpr size_t kFixedSizePortion = 52;
335 DebugDumpMessageData data;
336 data.hostClientId = hostClientId;
337 data.debugStr = debugStr;
338 data.debugStrSize = debugStrSize;
339 buildAndEnqueueMessage(PendingMessageType::DebugDumpData,
340 kFixedSizePortion + debugStrSize, msgBuilder, &data);
341 }
342
sendDebugDumpResponse(uint16_t hostClientId,bool success,uint32_t dataCount)343 void sendDebugDumpResponse(uint16_t hostClientId, bool success,
344 uint32_t dataCount) {
345 struct DebugDumpResponseData {
346 uint16_t hostClientId;
347 bool success;
348 uint32_t dataCount;
349 };
350
351 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
352 const auto *data = static_cast<const DebugDumpResponseData *>(cookie);
353 HostProtocolChre::encodeDebugDumpResponse(builder, data->hostClientId,
354 data->success, data->dataCount);
355 };
356
357 constexpr size_t kInitialSize = 52;
358 DebugDumpResponseData data;
359 data.hostClientId = hostClientId;
360 data.success = success;
361 data.dataCount = dataCount;
362 buildAndEnqueueMessage(PendingMessageType::DebugDumpResponse, kInitialSize,
363 msgBuilder, &data);
364 }
365
sendSelfTestResponse(uint16_t hostClientId,bool success)366 void sendSelfTestResponse(uint16_t hostClientId, bool success) {
367 struct SelfTestResponseData {
368 uint16_t hostClientId;
369 bool success;
370 };
371
372 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
373 const auto *data = static_cast<const SelfTestResponseData *>(cookie);
374 HostProtocolChre::encodeSelfTestResponse(builder, data->hostClientId,
375 data->success);
376 };
377
378 constexpr size_t kInitialSize = 52;
379 SelfTestResponseData data;
380 data.hostClientId = hostClientId;
381 data.success = success;
382 buildAndEnqueueMessage(PendingMessageType::SelfTestResponse, kInitialSize,
383 msgBuilder, &data);
384 }
385
386 /**
387 * Sends a request to the host for a time sync message.
388 */
sendTimeSyncRequest()389 void sendTimeSyncRequest() {
390 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
391 HostProtocolChre::encodeTimeSyncRequest(builder);
392 };
393
394 constexpr size_t kInitialSize = 52;
395 buildAndEnqueueMessage(PendingMessageType::TimeSyncRequest, kInitialSize,
396 msgBuilder, nullptr);
397
398 gLastTimeSyncRequestNanos = SystemTime::getMonotonicTime();
399 }
400
setTimeSyncRequestTimer(Nanoseconds delay)401 void setTimeSyncRequestTimer(Nanoseconds delay) {
402 static SystemTimer sTimeSyncRequestTimer;
403 static bool sTimeSyncRequestTimerInitialized = false;
404
405 // Check for timer init since this method might be called before CHRE
406 // init is called.
407 if (!sTimeSyncRequestTimerInitialized) {
408 if (!sTimeSyncRequestTimer.init()) {
409 FATAL_ERROR("Failed to initialize time sync request timer.");
410 } else {
411 sTimeSyncRequestTimerInitialized = true;
412 }
413 }
414 if (sTimeSyncRequestTimer.isActive()) {
415 sTimeSyncRequestTimer.cancel();
416 }
417 auto callback = [](void * /* data */) { sendTimeSyncRequest(); };
418 if (!sTimeSyncRequestTimer.set(callback, nullptr /* data */, delay)) {
419 LOGE("Failed to set time sync request timer.");
420 }
421 }
422
423 /**
424 * Helper function that prepares a nanoapp that can be loaded into the system
425 * from a file stored on disk.
426 *
427 * @param hostClientId the ID of client that originated this transaction
428 * @param transactionId the ID of the transaction
429 * @param appId the ID of the app to load
430 * @param appVersion the version of the app to load
431 * @param targetApiVersion the API version this nanoapp is targeted for
432 * @param appFilename Null-terminated ASCII string containing the file name that
433 * contains the app binary to be loaded.
434 *
435 * @return A valid pointer to a nanoapp that can be loaded into the system. A
436 * nullptr if the preparation process fails.
437 */
handleLoadNanoappFile(uint16_t hostClientId,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t targetApiVersion,const char * appFilename)438 UniquePtr<Nanoapp> handleLoadNanoappFile(uint16_t hostClientId,
439 uint32_t transactionId, uint64_t appId,
440 uint32_t appVersion,
441 uint32_t targetApiVersion,
442 const char *appFilename) {
443 LOGD("Load nanoapp request for app ID 0x%016" PRIx64 " ver 0x%" PRIx32
444 " target API 0x%08" PRIx32 " (txnId %" PRIu32 " client %" PRIu16 ")",
445 appId, appVersion, targetApiVersion, transactionId, hostClientId);
446
447 auto nanoapp = MakeUnique<Nanoapp>();
448
449 if (nanoapp.isNull()) {
450 LOG_OOM();
451 } else if (!nanoapp->setAppInfo(appId, appVersion, appFilename,
452 targetApiVersion) ||
453 !nanoapp->isLoaded()) {
454 nanoapp.reset(nullptr);
455 }
456
457 return nanoapp;
458 }
459
460 /**
461 * FastRPC method invoked by the host to block on messages
462 *
463 * @param buffer Output buffer to populate with message data
464 * @param bufferLen Size of the buffer, in bytes
465 * @param messageLen Output parameter to populate with the size of the message
466 * in bytes upon success
467 *
468 * @return 0 on success, nonzero on failure
469 */
chre_slpi_get_message_to_host(unsigned char * buffer,int bufferLen,unsigned int * messageLen)470 extern "C" int chre_slpi_get_message_to_host(unsigned char *buffer,
471 int bufferLen,
472 unsigned int *messageLen) {
473 CHRE_ASSERT(buffer != nullptr);
474 CHRE_ASSERT(bufferLen > 0);
475 CHRE_ASSERT(messageLen != nullptr);
476 int result = CHRE_FASTRPC_ERROR;
477
478 if (bufferLen <= 0 || buffer == nullptr || messageLen == nullptr) {
479 // Note that we can't use regular logs here as they can result in sending
480 // a message, leading to an infinite loop if the error is persistent
481 FARF(FATAL, "Invalid buffer size %d or bad pointers (buf %d len %d)",
482 bufferLen, (buffer == nullptr), (messageLen == nullptr));
483 } else {
484 size_t bufferSize = static_cast<size_t>(bufferLen);
485 PendingMessage pendingMsg = gOutboundQueue.pop();
486
487 switch (pendingMsg.type) {
488 case PendingMessageType::Shutdown:
489 result = CHRE_FASTRPC_ERROR_SHUTTING_DOWN;
490 break;
491
492 case PendingMessageType::NanoappMessageToHost:
493 result = generateMessageToHost(pendingMsg.data.msgToHost, buffer,
494 bufferSize, messageLen);
495 break;
496
497 case PendingMessageType::HubInfoResponse:
498 result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer,
499 bufferSize, messageLen);
500 break;
501
502 case PendingMessageType::NanoappListResponse:
503 case PendingMessageType::LoadNanoappResponse:
504 case PendingMessageType::UnloadNanoappResponse:
505 case PendingMessageType::DebugDumpData:
506 case PendingMessageType::DebugDumpResponse:
507 case PendingMessageType::TimeSyncRequest:
508 case PendingMessageType::LowPowerMicAccessRequest:
509 case PendingMessageType::LowPowerMicAccessRelease:
510 case PendingMessageType::EncodedLogMessage:
511 case PendingMessageType::SelfTestResponse:
512 case PendingMessageType::MetricLog:
513 case PendingMessageType::NanConfigurationRequest:
514 result = generateMessageFromBuilder(
515 pendingMsg.data.builder, buffer, bufferSize, messageLen,
516 pendingMsg.type == PendingMessageType::EncodedLogMessage);
517 break;
518
519 default:
520 CHRE_ASSERT_LOG(false, "Unexpected pending message type");
521 }
522 }
523
524 // Opportunistically send a time sync message (1 hour period threshold)
525 constexpr Seconds kOpportunisticTimeSyncPeriod = Seconds(60 * 60 * 1);
526 if (SystemTime::getMonotonicTime() >
527 gLastTimeSyncRequestNanos + kOpportunisticTimeSyncPeriod) {
528 sendTimeSyncRequest();
529 }
530
531 return result;
532 }
533
534 /**
535 * FastRPC method invoked by the host to send a message to the system
536 *
537 * @param buffer
538 * @param size
539 *
540 * @return 0 on success, nonzero on failure
541 */
chre_slpi_deliver_message_from_host(const unsigned char * message,int messageLen)542 extern "C" int chre_slpi_deliver_message_from_host(const unsigned char *message,
543 int messageLen) {
544 CHRE_ASSERT(message != nullptr);
545 CHRE_ASSERT(messageLen > 0);
546 int result = CHRE_FASTRPC_ERROR;
547
548 if (message == nullptr || messageLen <= 0) {
549 LOGE("Got null or invalid size (%d) message from host", messageLen);
550 } else if (!HostProtocolChre::decodeMessageFromHost(
551 message, static_cast<size_t>(messageLen))) {
552 LOGE("Failed to decode/handle message");
553 } else {
554 result = CHRE_FASTRPC_SUCCESS;
555 }
556
557 return result;
558 }
559
560 } // anonymous namespace
561
sendDebugDumpResultToHost(uint16_t hostClientId,const char * debugStr,size_t debugStrSize,bool complete,uint32_t dataCount)562 void sendDebugDumpResultToHost(uint16_t hostClientId, const char *debugStr,
563 size_t debugStrSize, bool complete,
564 uint32_t dataCount) {
565 if (debugStrSize > 0) {
566 sendDebugDumpData(hostClientId, debugStr, debugStrSize);
567 }
568
569 if (complete) {
570 sendDebugDumpResponse(hostClientId, true /*success*/, dataCount);
571 }
572 }
573
flushMessagesSentByNanoapp(uint64_t)574 void HostLink::flushMessagesSentByNanoapp(uint64_t /*appId*/) {
575 // TODO: this is not completely safe since it's timer-based, but should work
576 // well enough for the initial implementation. To be fully safe, we'd need
577 // some synchronization with the thread that runs
578 // chre_slpi_get_message_to_host(), e.g. a mutex that is held by that thread
579 // prior to calling pop() and only released after onMessageToHostComplete
580 // would've been called. If we acquire that mutex here, and hold it while
581 // purging any messages sent by the nanoapp in the queue, we can be certain
582 // that onMessageToHostComplete will not be called after this function returns
583 // for messages sent by that nanoapp
584 flushOutboundQueue();
585
586 // One extra sleep to try to ensure that any messages popped just before
587 // checking empty() are fully processed before we return
588 constexpr time_timetick_type kFinalDelayUsec = 10000;
589 timer_sleep(kFinalDelayUsec, T_USEC, true /* non_deferrable */);
590 }
591
sendMessage(const MessageToHost * message)592 bool HostLink::sendMessage(const MessageToHost *message) {
593 return enqueueMessage(
594 PendingMessage(PendingMessageType::NanoappMessageToHost, message));
595 }
596
sendMessageDeliveryStatus(uint32_t,uint8_t)597 bool HostLink::sendMessageDeliveryStatus(uint32_t /* messageSequenceNumber */,
598 uint8_t /* errorCode */) {
599 return false;
600 }
601
sendMetricLog(uint32_t metricId,const uint8_t * encodedMetric,size_t encodedMetricLen)602 bool HostLink::sendMetricLog(uint32_t metricId, const uint8_t *encodedMetric,
603 size_t encodedMetricLen) {
604 struct MetricLogData {
605 uint32_t metricId;
606 const uint8_t *encodedMetric;
607 size_t encodedMetricLen;
608 };
609
610 MetricLogData data;
611 data.metricId = metricId;
612 data.encodedMetric = encodedMetric;
613 data.encodedMetricLen = encodedMetricLen;
614
615 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
616 const auto *data = static_cast<const MetricLogData *>(cookie);
617 HostProtocolChre::encodeMetricLog(
618 builder, data->metricId, data->encodedMetric, data->encodedMetricLen);
619 };
620
621 constexpr size_t kInitialSize = 52;
622 buildAndEnqueueMessage(PendingMessageType::MetricLog, kInitialSize,
623 msgBuilder, &data);
624 return true;
625 }
626
flushOutboundQueue()627 bool HostLinkBase::flushOutboundQueue() {
628 int waitCount = 5;
629
630 FARF(MEDIUM, "Draining message queue");
631 while (!gOutboundQueue.empty() && waitCount-- > 0) {
632 timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */);
633 }
634
635 return (waitCount >= 0);
636 }
637
sendLogMessage(const uint8_t * logMessage,size_t logMessageSize)638 void HostLinkBase::sendLogMessage(const uint8_t *logMessage,
639 size_t logMessageSize) {
640 struct LogMessageData {
641 const uint8_t *logMsg;
642 size_t logMsgSize;
643 };
644
645 LogMessageData logMessageData;
646
647 logMessageData.logMsg = logMessage;
648 logMessageData.logMsgSize = logMessageSize;
649
650 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
651 const auto *data = static_cast<const LogMessageData *>(cookie);
652 HostProtocolChre::encodeLogMessages(builder, data->logMsg,
653 data->logMsgSize);
654 };
655
656 constexpr size_t kInitialSize = 128;
657 buildAndEnqueueMessage(PendingMessageType::EncodedLogMessage, kInitialSize,
658 msgBuilder, &logMessageData);
659 }
660
sendLogMessageV2(const uint8_t * logMessage,size_t logMessageSize,uint32_t numLogsDropped)661 void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
662 size_t logMessageSize,
663 uint32_t numLogsDropped) {
664 struct LogMessageData {
665 const uint8_t *logMsg;
666 size_t logMsgSize;
667 uint32_t numLogsDropped;
668 };
669
670 LogMessageData logMessageData{logMessage, logMessageSize, numLogsDropped};
671
672 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
673 const auto *data = static_cast<const LogMessageData *>(cookie);
674 HostProtocolChre::encodeLogMessagesV2(
675 builder, data->logMsg, data->logMsgSize, data->numLogsDropped);
676 };
677
678 constexpr size_t kInitialSize = 128;
679 buildAndEnqueueMessage(PendingMessageType::EncodedLogMessage, kInitialSize,
680 msgBuilder, &logMessageData);
681 }
682
sendNanConfiguration(bool enable)683 void HostLinkBase::sendNanConfiguration(bool enable) {
684 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
685 const auto *data = static_cast<const bool *>(cookie);
686 HostProtocolChre::encodeNanConfigurationRequest(builder, *data);
687 };
688
689 constexpr size_t kInitialSize = 48;
690 buildAndEnqueueMessage(PendingMessageType::NanConfigurationRequest,
691 kInitialSize, msgBuilder, &enable);
692 }
693
shutdown()694 void HostLinkBase::shutdown() {
695 // Push a null message so the blocking call in chre_slpi_get_message_to_host()
696 // returns and the host can exit cleanly. If the queue is full, try again to
697 // avoid getting stuck (no other new messages should be entering the queue at
698 // this time). Don't wait too long as the host-side binary may have died in
699 // a state where it's not blocked in chre_slpi_get_message_to_host().
700 int retryCount = 5;
701 FARF(MEDIUM, "Shutting down host link");
702 while (!enqueueMessage(PendingMessage(PendingMessageType::Shutdown)) &&
703 --retryCount > 0) {
704 timer_sleep(kPollingIntervalUsec, T_USEC, true /* non_deferrable */);
705 }
706
707 if (retryCount <= 0) {
708 // Don't use LOGE, as it may involve trying to send a message
709 FARF(ERROR,
710 "No room in outbound queue for shutdown message and host not "
711 "draining queue!");
712 } else {
713 // We were able to push the shutdown message. Wait for the queue to
714 // completely flush before returning.
715 if (!flushOutboundQueue()) {
716 FARF(ERROR, "Host took too long to drain outbound queue; exiting anyway");
717 } else {
718 FARF(MEDIUM, "Finished draining queue");
719 }
720 }
721 }
722
sendAudioRequest()723 void sendAudioRequest() {
724 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
725 HostProtocolChre::encodeLowPowerMicAccessRequest(builder);
726 };
727
728 constexpr size_t kInitialSize = 32;
729 buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRequest,
730 kInitialSize, msgBuilder, nullptr);
731 }
732
sendAudioRelease()733 void sendAudioRelease() {
734 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
735 HostProtocolChre::encodeLowPowerMicAccessRelease(builder);
736 };
737
738 constexpr size_t kInitialSize = 32;
739 buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRelease,
740 kInitialSize, msgBuilder, nullptr);
741 }
742
sendFragmentResponse(uint16_t hostClientId,uint32_t transactionId,uint32_t fragmentId,bool success)743 void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
744 uint32_t transactionId,
745 uint32_t fragmentId,
746 bool success) {
747 struct FragmentedLoadInfoResponse {
748 uint16_t hostClientId;
749 uint32_t transactionId;
750 uint32_t fragmentId;
751 bool success;
752 };
753
754 auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
755 auto *cbData = static_cast<FragmentedLoadInfoResponse *>(cookie);
756 HostProtocolChre::encodeLoadNanoappResponse(
757 builder, cbData->hostClientId, cbData->transactionId, cbData->success,
758 cbData->fragmentId);
759 };
760
761 FragmentedLoadInfoResponse response = {
762 .hostClientId = hostClientId,
763 .transactionId = transactionId,
764 .fragmentId = fragmentId,
765 .success = success,
766 };
767 constexpr size_t kInitialBufferSize = 48;
768 buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
769 kInitialBufferSize, msgBuilder, &response);
770 }
771
handleNanoappMessage(uint64_t appId,uint32_t messageType,uint16_t hostEndpoint,const void * messageData,size_t messageDataLen,bool isReliable,uint32_t messageSequenceNumber)772 void HostMessageHandlers::handleNanoappMessage(
773 uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
774 const void *messageData, size_t messageDataLen, bool isReliable,
775 uint32_t messageSequenceNumber) {
776 LOGD("Parsed nanoapp message from host: app ID 0x%016" PRIx64
777 ", endpoint "
778 "0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
779 appId, hostEndpoint, messageType, messageDataLen);
780
781 HostCommsManager &manager =
782 EventLoopManagerSingleton::get()->getHostCommsManager();
783 manager.sendMessageToNanoappFromHost(appId, messageType, hostEndpoint,
784 messageData, messageDataLen, isReliable,
785 messageSequenceNumber);
786 }
787
handleMessageDeliveryStatus(uint32_t,uint8_t)788 void HostMessageHandlers::handleMessageDeliveryStatus(
789 uint32_t /* messageSequenceNumber */, uint8_t /* errorCode */) {}
790
handleHubInfoRequest(uint16_t hostClientId)791 void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
792 // We generate the response in the context of chre_slpi_get_message_to_host
793 LOGD("Hub info request from client ID %" PRIu16, hostClientId);
794 enqueueMessage(
795 PendingMessage(PendingMessageType::HubInfoResponse, hostClientId));
796 }
797
handleNanoappListRequest(uint16_t hostClientId)798 void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
799 auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
800 uint16_t cbHostClientId = NestedDataPtr<uint16_t>(data);
801
802 NanoappListData cbData = {};
803 cbData.hostClientId = cbHostClientId;
804
805 size_t expectedNanoappCount =
806 EventLoopManagerSingleton::get()->getEventLoop().getNanoappCount();
807 if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) {
808 LOG_OOM();
809 } else {
810 constexpr size_t kFixedOverhead = 48;
811 constexpr size_t kPerNanoappSize = 32;
812 size_t initialBufferSize =
813 (kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
814
815 buildAndEnqueueMessage(PendingMessageType::NanoappListResponse,
816 initialBufferSize, buildNanoappListResponse,
817 &cbData);
818 }
819 };
820
821 LOGD("Nanoapp list request from client ID %" PRIu16, hostClientId);
822 EventLoopManagerSingleton::get()->deferCallback(
823 SystemCallbackType::NanoappListResponse,
824 NestedDataPtr<uint16_t>(hostClientId), callback);
825 }
826
handleLoadNanoappRequest(uint16_t hostClientId,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t appFlags,uint32_t targetApiVersion,const void * buffer,size_t bufferLen,const char * appFileName,uint32_t fragmentId,size_t appBinaryLen,bool respondBeforeStart)827 void HostMessageHandlers::handleLoadNanoappRequest(
828 uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
829 uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
830 const void *buffer, size_t bufferLen, const char *appFileName,
831 uint32_t fragmentId, size_t appBinaryLen, bool respondBeforeStart) {
832 if (appFileName == nullptr) {
833 loadNanoappData(hostClientId, transactionId, appId, appVersion, appFlags,
834 targetApiVersion, buffer, bufferLen, fragmentId,
835 appBinaryLen, respondBeforeStart);
836 return;
837 }
838
839 UniquePtr<Nanoapp> pendingNanoapp =
840 handleLoadNanoappFile(hostClientId, transactionId, appId, appVersion,
841 targetApiVersion, appFileName);
842
843 if (!pendingNanoapp.isNull()) {
844 auto cbData = MakeUnique<LoadNanoappCallbackData>();
845 if (cbData.isNull()) {
846 LOG_OOM();
847 } else {
848 cbData->transactionId = transactionId;
849 cbData->hostClientId = hostClientId;
850 cbData->appId = appId;
851 cbData->fragmentId = fragmentId;
852 cbData->nanoapp = std::move(pendingNanoapp);
853
854 // Note that if this fails, we'll generate the error response in
855 // the normal deferred callback
856 EventLoopManagerSingleton::get()->deferCallback(
857 SystemCallbackType::FinishLoadingNanoapp, std::move(cbData),
858 finishLoadingNanoappCallback);
859 }
860 }
861 }
862
handleUnloadNanoappRequest(uint16_t hostClientId,uint32_t transactionId,uint64_t appId,bool allowSystemNanoappUnload)863 void HostMessageHandlers::handleUnloadNanoappRequest(
864 uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
865 bool allowSystemNanoappUnload) {
866 LOGD("Unload nanoapp request (txnID %" PRIu32 ") for appId 0x%016" PRIx64
867 " system %d",
868 transactionId, appId, allowSystemNanoappUnload);
869 auto cbData = MakeUnique<UnloadNanoappCallbackData>();
870 if (cbData == nullptr) {
871 LOG_OOM();
872 } else {
873 cbData->appId = appId;
874 cbData->transactionId = transactionId;
875 cbData->hostClientId = hostClientId;
876 cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
877
878 EventLoopManagerSingleton::get()->deferCallback(
879 SystemCallbackType::HandleUnloadNanoapp, std::move(cbData),
880 handleUnloadNanoappCallback);
881 }
882 }
883
handleTimeSyncMessage(int64_t offset)884 void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
885 SystemTime::setEstimatedHostTimeOffset(offset);
886
887 // Schedule a time sync request since offset may drift
888 constexpr Seconds kClockDriftTimeSyncPeriod =
889 Seconds(60 * 60 * 6); // 6 hours
890 setTimeSyncRequestTimer(kClockDriftTimeSyncPeriod);
891 }
892
handleDebugDumpRequest(uint16_t hostClientId)893 void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
894 if (!chre::EventLoopManagerSingleton::get()
895 ->getDebugDumpManager()
896 .onDebugDumpRequested(hostClientId)) {
897 LOGE("Couldn't trigger debug dump process");
898 sendDebugDumpResponse(hostClientId, false /*success*/, 0 /*dataCount*/);
899 }
900 }
901
handleSettingChangeMessage(fbs::Setting setting,fbs::SettingState state)902 void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
903 fbs::SettingState state) {
904 Setting chreSetting;
905 bool chreSettingEnabled;
906 if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) &&
907 HostProtocolChre::getSettingEnabledFromFbs(state, &chreSettingEnabled)) {
908 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
909 chreSetting, chreSettingEnabled);
910 }
911 }
912
handleSelfTestRequest(uint16_t hostClientId)913 void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
914 // TODO(b/182201569): Run test
915 bool success = true;
916 sendSelfTestResponse(hostClientId, success);
917 }
918
handlePulseRequest()919 void HostMessageHandlers::handlePulseRequest() {}
920
handleNanConfigurationUpdate(bool enabled)921 void HostMessageHandlers::handleNanConfigurationUpdate(bool enabled) {
922 #ifdef CHRE_WIFI_NAN_SUPPORT_ENABLED
923 EventLoopManagerSingleton::get()
924 ->getWifiRequestManager()
925 .updateNanAvailability(enabled);
926 #else
927 UNUSED_VAR(enabled);
928 #endif // CHRE_WIFI_NAN_SUPPORT_ENABLED
929 }
930
931 } // namespace chre
932