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