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