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