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