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 ANDROID_HARDWARE_CONTEXTHUB_COMMON_CONTEXTHUB_H
18 #define ANDROID_HARDWARE_CONTEXTHUB_COMMON_CONTEXTHUB_H
19
20 #include <condition_variable>
21 #include <functional>
22 #include <mutex>
23 #include <optional>
24
25 #include <android/hardware/contexthub/1.0/IContexthub.h>
26 #include <hidl/MQDescriptor.h>
27 #include <hidl/Status.h>
28 #include <log/log.h>
29
30 #include "IContextHubCallbackWrapper.h"
31 #include "chre_host/fragmented_load_transaction.h"
32 #include "chre_host/host_protocol_host.h"
33 #include "chre_host/socket_client.h"
34 #include "permissions_util.h"
35
36 namespace android {
37 namespace hardware {
38 namespace contexthub {
39 namespace common {
40 namespace implementation {
41
42 using ::android::sp;
43 using ::android::chre::FragmentedLoadRequest;
44 using ::android::chre::FragmentedLoadTransaction;
45 using ::android::chre::getStringFromByteVector;
46 using ::android::chre::HostProtocolHost;
47 using ::android::hardware::hidl_handle;
48 using ::android::hardware::hidl_string;
49 using ::android::hardware::hidl_vec;
50 using ::android::hardware::Return;
51 using ::android::hardware::contexthub::common::implementation::
52 chreToAndroidPermissions;
53 using ::android::hardware::contexthub::V1_0::AsyncEventType;
54 using ::android::hardware::contexthub::V1_0::ContextHub;
55 using ::android::hardware::contexthub::V1_0::IContexthubCallback;
56 using ::android::hardware::contexthub::V1_0::NanoAppBinary;
57 using ::android::hardware::contexthub::V1_0::Result;
58 using ::android::hardware::contexthub::V1_0::TransactionResult;
59 using ::android::hardware::contexthub::V1_2::ContextHubMsg;
60 using ::android::hardware::contexthub::V1_2::HubAppInfo;
61 using ::android::hardware::contexthub::V1_X::implementation::
62 IContextHubCallbackWrapperBase;
63 using ::android::hardware::contexthub::V1_X::implementation::
64 IContextHubCallbackWrapperV1_0;
65 using ::flatbuffers::FlatBufferBuilder;
66
67 constexpr uint32_t kDefaultHubId = 0;
68
extractChreApiMajorVersion(uint32_t chreVersion)69 inline constexpr uint8_t extractChreApiMajorVersion(uint32_t chreVersion) {
70 return static_cast<uint8_t>(chreVersion >> 24);
71 }
72
extractChreApiMinorVersion(uint32_t chreVersion)73 inline constexpr uint8_t extractChreApiMinorVersion(uint32_t chreVersion) {
74 return static_cast<uint8_t>(chreVersion >> 16);
75 }
76
extractChrePatchVersion(uint32_t chreVersion)77 inline constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
78 return static_cast<uint16_t>(chreVersion);
79 }
80
81 /**
82 * @return file descriptor contained in the hidl_handle, or -1 if there is none
83 */
hidlHandleToFileDescriptor(const hidl_handle & hh)84 inline int hidlHandleToFileDescriptor(const hidl_handle &hh) {
85 const native_handle_t *handle = hh.getNativeHandle();
86 return (handle != nullptr && handle->numFds >= 1) ? handle->data[0] : -1;
87 }
88
89 template <class IContexthubT>
90 class GenericContextHubBase : public IContexthubT {
91 public:
GenericContextHubBase()92 GenericContextHubBase() {
93 constexpr char kChreSocketName[] = "chre";
94
95 mSocketCallbacks = new SocketCallbacks(*this);
96 if (!mClient.connectInBackground(kChreSocketName, mSocketCallbacks)) {
97 ALOGE("Couldn't start socket client");
98 }
99
100 mDeathRecipient = new DeathRecipient(this);
101 }
102
debug(const hidl_handle & fd,const hidl_vec<hidl_string> &)103 Return<void> debug(const hidl_handle &fd,
104 const hidl_vec<hidl_string> & /* options */) override {
105 // Timeout inside CHRE is typically 5 seconds, grant 500ms extra here to let
106 // the data reach us
107 constexpr auto kDebugDumpTimeout = std::chrono::milliseconds(5500);
108
109 mDebugFd = hidlHandleToFileDescriptor(fd);
110 if (mDebugFd < 0) {
111 ALOGW("Can't dump debug info to invalid fd");
112 } else {
113 writeToDebugFile("-- Dumping CHRE/ASH debug info --\n");
114
115 ALOGV("Sending debug dump request");
116 FlatBufferBuilder builder;
117 HostProtocolHost::encodeDebugDumpRequest(builder);
118 std::unique_lock<std::mutex> lock(mDebugDumpMutex);
119 mDebugDumpPending = true;
120 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
121 ALOGW("Couldn't send debug dump request");
122 } else {
123 mDebugDumpCond.wait_for(lock, kDebugDumpTimeout,
124 [this]() { return !mDebugDumpPending; });
125 if (mDebugDumpPending) {
126 ALOGI("Timed out waiting on debug dump data");
127 mDebugDumpPending = false;
128 }
129 }
130 writeToDebugFile("\n-- End of CHRE/ASH debug info --\n");
131
132 mDebugFd = kInvalidFd;
133 ALOGV("Debug dump complete");
134 }
135
136 return Void();
137 }
138
139 // Methods from ::android::hardware::contexthub::V1_0::IContexthub follow.
getHubs(V1_0::IContexthub::getHubs_cb _hidl_cb)140 Return<void> getHubs(V1_0::IContexthub::getHubs_cb _hidl_cb) override {
141 constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
142 std::vector<ContextHub> hubs;
143 ALOGV("%s", __func__);
144
145 // If we're not connected yet, give it some time
146 // TODO refactor from polling into conditional wait
147 int maxSleepIterations = 250;
148 while (!mHubInfoValid && !mClient.isConnected() &&
149 --maxSleepIterations > 0) {
150 std::this_thread::sleep_for(std::chrono::milliseconds(20));
151 }
152
153 if (!mClient.isConnected()) {
154 ALOGE("Couldn't connect to hub daemon");
155 } else if (!mHubInfoValid) {
156 // We haven't cached the hub details yet, so send a request and block
157 // waiting on a response
158 std::unique_lock<std::mutex> lock(mHubInfoMutex);
159 FlatBufferBuilder builder;
160 HostProtocolHost::encodeHubInfoRequest(builder);
161
162 ALOGD("Sending hub info request");
163 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
164 ALOGE("Couldn't send hub info request");
165 } else {
166 mHubInfoCond.wait_for(lock, kHubInfoQueryTimeout,
167 [this]() { return mHubInfoValid; });
168 }
169 }
170
171 if (mHubInfoValid) {
172 hubs.push_back(mHubInfo);
173 } else {
174 ALOGE("Unable to get hub info from CHRE");
175 }
176
177 _hidl_cb(hubs);
178 return Void();
179 }
180
registerCallback(uint32_t hubId,const sp<IContexthubCallback> & cb)181 Return<Result> registerCallback(uint32_t hubId,
182 const sp<IContexthubCallback> &cb) override {
183 sp<IContextHubCallbackWrapperBase> wrappedCallback;
184 if (cb != nullptr) {
185 wrappedCallback = new IContextHubCallbackWrapperV1_0(cb);
186 }
187 return registerCallbackCommon(hubId, wrappedCallback);
188 }
189
190 // Common logic shared between pre-V1.2 and V1.2 HALs.
registerCallbackCommon(uint32_t hubId,const sp<IContextHubCallbackWrapperBase> & cb)191 Return<Result> registerCallbackCommon(
192 uint32_t hubId, const sp<IContextHubCallbackWrapperBase> &cb) {
193 Result result;
194 ALOGV("%s", __func__);
195
196 // TODO: currently we only support 1 hub behind this HAL implementation
197 if (hubId == kDefaultHubId) {
198 std::lock_guard<std::mutex> lock(mCallbacksLock);
199
200 if (cb != nullptr) {
201 if (mCallbacks != nullptr) {
202 ALOGD("Modifying callback for hubId %" PRIu32, hubId);
203 mCallbacks->unlinkToDeath(mDeathRecipient);
204 }
205 Return<bool> linkReturn = cb->linkToDeath(mDeathRecipient, hubId);
206 if (!linkReturn.withDefault(false)) {
207 ALOGW("Could not link death recipient to hubId %" PRIu32, hubId);
208 }
209 }
210
211 mCallbacks = cb;
212 result = Result::OK;
213 } else {
214 result = Result::BAD_PARAMS;
215 }
216
217 return result;
218 }
219
sendMessageToHub(uint32_t hubId,const V1_0::ContextHubMsg & msg)220 Return<Result> sendMessageToHub(uint32_t hubId,
221 const V1_0::ContextHubMsg &msg) override {
222 Result result;
223 ALOGV("%s", __func__);
224
225 if (hubId != kDefaultHubId) {
226 result = Result::BAD_PARAMS;
227 } else {
228 FlatBufferBuilder builder(1024);
229 HostProtocolHost::encodeNanoappMessage(builder, msg.appName, msg.msgType,
230 msg.hostEndPoint, msg.msg.data(),
231 msg.msg.size());
232
233 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
234 result = Result::UNKNOWN_FAILURE;
235 } else {
236 result = Result::OK;
237 }
238 }
239
240 return result;
241 }
242
loadNanoApp(uint32_t hubId,const NanoAppBinary & appBinary,uint32_t transactionId)243 Return<Result> loadNanoApp(uint32_t hubId, const NanoAppBinary &appBinary,
244 uint32_t transactionId) override {
245 Result result;
246 ALOGV("%s", __func__);
247
248 if (hubId != kDefaultHubId) {
249 result = Result::BAD_PARAMS;
250 } else {
251 std::lock_guard<std::mutex> lock(mPendingLoadTransactionMutex);
252
253 if (mPendingLoadTransaction.has_value()) {
254 ALOGE("Pending load transaction exists. Overriding pending request");
255 }
256
257 uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
258 (appBinary.targetChreApiMinorVersion << 16);
259 mPendingLoadTransaction = FragmentedLoadTransaction(
260 transactionId, appBinary.appId, appBinary.appVersion, appBinary.flags,
261 targetApiVersion, appBinary.customBinary);
262
263 result =
264 sendFragmentedLoadNanoAppRequest(mPendingLoadTransaction.value());
265 if (result != Result::OK) {
266 mPendingLoadTransaction.reset();
267 }
268 }
269
270 ALOGD(
271 "Attempted to send load nanoapp request for app of size %zu with ID "
272 "0x%016" PRIx64 " as transaction ID %" PRIu32 ": result %" PRIu32,
273 appBinary.customBinary.size(), appBinary.appId, transactionId, result);
274
275 return result;
276 }
277
unloadNanoApp(uint32_t hubId,uint64_t appId,uint32_t transactionId)278 Return<Result> unloadNanoApp(uint32_t hubId, uint64_t appId,
279 uint32_t transactionId) override {
280 Result result;
281 ALOGV("%s", __func__);
282
283 if (hubId != kDefaultHubId) {
284 result = Result::BAD_PARAMS;
285 } else {
286 FlatBufferBuilder builder(64);
287 HostProtocolHost::encodeUnloadNanoappRequest(
288 builder, transactionId, appId, false /* allowSystemNanoappUnload */);
289 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
290 result = Result::UNKNOWN_FAILURE;
291 } else {
292 result = Result::OK;
293 }
294 }
295
296 ALOGD("Attempted to send unload nanoapp request for app ID 0x%016" PRIx64
297 " as transaction ID %" PRIu32 ": result %" PRIu32,
298 appId, transactionId, result);
299
300 return result;
301 }
302
enableNanoApp(uint32_t,uint64_t appId,uint32_t)303 Return<Result> enableNanoApp(uint32_t /* hubId */, uint64_t appId,
304 uint32_t /* transactionId */) override {
305 // TODO
306 ALOGW("Attempted to enable app ID 0x%016" PRIx64 ", but not supported",
307 appId);
308 return Result::TRANSACTION_FAILED;
309 }
310
disableNanoApp(uint32_t,uint64_t appId,uint32_t)311 Return<Result> disableNanoApp(uint32_t /* hubId */, uint64_t appId,
312 uint32_t /* transactionId */) override {
313 // TODO
314 ALOGW("Attempted to disable app ID 0x%016" PRIx64 ", but not supported",
315 appId);
316 return Result::TRANSACTION_FAILED;
317 }
318
queryApps(uint32_t hubId)319 Return<Result> queryApps(uint32_t hubId) override {
320 Result result;
321 ALOGV("%s", __func__);
322
323 if (hubId != kDefaultHubId) {
324 result = Result::BAD_PARAMS;
325 } else {
326 FlatBufferBuilder builder(64);
327 HostProtocolHost::encodeNanoappListRequest(builder);
328 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
329 result = Result::UNKNOWN_FAILURE;
330 } else {
331 result = Result::OK;
332 }
333 }
334
335 return result;
336 }
337
338 protected:
339 ::android::chre::SocketClient mClient;
340 sp<IContextHubCallbackWrapperBase> mCallbacks;
341 std::mutex mCallbacksLock;
342
343 class SocketCallbacks : public ::android::chre::SocketClient::ICallbacks,
344 public ::android::chre::IChreMessageHandlers {
345 public:
SocketCallbacks(GenericContextHubBase & parent)346 explicit SocketCallbacks(GenericContextHubBase &parent) : mParent(parent) {}
347
onMessageReceived(const void * data,size_t length)348 void onMessageReceived(const void *data, size_t length) override {
349 if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
350 ALOGE("Failed to decode message");
351 }
352 }
353
onConnected()354 void onConnected() override {
355 if (mHaveConnected) {
356 ALOGI("Reconnected to CHRE daemon");
357 invokeClientCallback([&]() {
358 return mParent.mCallbacks->handleHubEvent(AsyncEventType::RESTARTED);
359 });
360 }
361 mHaveConnected = true;
362 }
363
onDisconnected()364 void onDisconnected() override {
365 ALOGW("Lost connection to CHRE daemon");
366 }
367
handleNanoappMessage(const::chre::fbs::NanoappMessageT & message)368 void handleNanoappMessage(
369 const ::chre::fbs::NanoappMessageT &message) override {
370 ContextHubMsg msg;
371 msg.msg_1_0.appName = message.app_id;
372 msg.msg_1_0.hostEndPoint = message.host_endpoint;
373 msg.msg_1_0.msgType = message.message_type;
374 msg.msg_1_0.msg = message.message;
375 // Set of nanoapp permissions required to communicate with this nanoapp.
376 msg.permissions = chreToAndroidPermissions(message.permissions);
377 // Set of permissions required to consume this message and what will be
378 // attributed when the host endpoint consumes this on the Android side.
379 hidl_vec<hidl_string> msgContentPerms =
380 chreToAndroidPermissions(message.message_permissions);
381
382 invokeClientCallback([&]() {
383 return mParent.mCallbacks->handleClientMsg(msg, msgContentPerms);
384 });
385 }
386
handleHubInfoResponse(const::chre::fbs::HubInfoResponseT & response)387 void handleHubInfoResponse(
388 const ::chre::fbs::HubInfoResponseT &response) override {
389 ALOGD("Got hub info response");
390
391 std::lock_guard<std::mutex> lock(mParent.mHubInfoMutex);
392 if (mParent.mHubInfoValid) {
393 ALOGI("Ignoring duplicate/unsolicited hub info response");
394 } else {
395 mParent.mHubInfo.name = getStringFromByteVector(response.name);
396 mParent.mHubInfo.vendor = getStringFromByteVector(response.vendor);
397 mParent.mHubInfo.toolchain =
398 getStringFromByteVector(response.toolchain);
399 mParent.mHubInfo.platformVersion = response.platform_version;
400 mParent.mHubInfo.toolchainVersion = response.toolchain_version;
401 mParent.mHubInfo.hubId = kDefaultHubId;
402
403 mParent.mHubInfo.peakMips = response.peak_mips;
404 mParent.mHubInfo.stoppedPowerDrawMw = response.stopped_power;
405 mParent.mHubInfo.sleepPowerDrawMw = response.sleep_power;
406 mParent.mHubInfo.peakPowerDrawMw = response.peak_power;
407
408 mParent.mHubInfo.maxSupportedMsgLen = response.max_msg_len;
409 mParent.mHubInfo.chrePlatformId = response.platform_id;
410
411 uint32_t version = response.chre_platform_version;
412 mParent.mHubInfo.chreApiMajorVersion =
413 extractChreApiMajorVersion(version);
414 mParent.mHubInfo.chreApiMinorVersion =
415 extractChreApiMinorVersion(version);
416 mParent.mHubInfo.chrePatchVersion = extractChrePatchVersion(version);
417
418 mParent.mHubInfoValid = true;
419 mParent.mHubInfoCond.notify_all();
420 }
421 }
422
handleNanoappListResponse(const::chre::fbs::NanoappListResponseT & response)423 void handleNanoappListResponse(
424 const ::chre::fbs::NanoappListResponseT &response) override {
425 std::vector<HubAppInfo> appInfoList;
426
427 ALOGV("Got nanoapp list response with %zu apps",
428 response.nanoapps.size());
429 for (const std::unique_ptr<::chre::fbs::NanoappListEntryT> &nanoapp :
430 response.nanoapps) {
431 // TODO: determine if this is really required, and if so, have
432 // HostProtocolHost strip out null entries as part of decode
433 if (nanoapp == nullptr) {
434 continue;
435 }
436
437 ALOGV("App 0x%016" PRIx64 " ver 0x%" PRIx32 " permissions 0x%" PRIx32
438 " enabled %d system %d",
439 nanoapp->app_id, nanoapp->version, nanoapp->permissions,
440 nanoapp->enabled, nanoapp->is_system);
441 if (!nanoapp->is_system) {
442 HubAppInfo appInfo;
443
444 appInfo.info_1_0.appId = nanoapp->app_id;
445 appInfo.info_1_0.version = nanoapp->version;
446 appInfo.info_1_0.enabled = nanoapp->enabled;
447 appInfo.permissions = chreToAndroidPermissions(nanoapp->permissions);
448
449 appInfoList.push_back(appInfo);
450 }
451 }
452
453 invokeClientCallback(
454 [&]() { return mParent.mCallbacks->handleAppsInfo(appInfoList); });
455 }
456
handleLoadNanoappResponse(const::chre::fbs::LoadNanoappResponseT & response)457 void handleLoadNanoappResponse(
458 const ::chre::fbs::LoadNanoappResponseT &response) override {
459 ALOGV("Got load nanoapp response for transaction %" PRIu32
460 " fragment %" PRIu32 " with result %d",
461 response.transaction_id, response.fragment_id, response.success);
462 std::unique_lock<std::mutex> lock(mParent.mPendingLoadTransactionMutex);
463
464 // TODO: Handle timeout in receiving load response
465 if (!mParent.mPendingLoadTransaction.has_value()) {
466 ALOGE(
467 "Dropping unexpected load response (no pending transaction "
468 "exists)");
469 } else {
470 FragmentedLoadTransaction &transaction =
471 mParent.mPendingLoadTransaction.value();
472
473 if (!mParent.isExpectedLoadResponseLocked(response)) {
474 ALOGE(
475 "Dropping unexpected load response, expected transaction %" PRIu32
476 " fragment %" PRIu32 ", received transaction %" PRIu32
477 " fragment %" PRIu32,
478 transaction.getTransactionId(), mParent.mCurrentFragmentId,
479 response.transaction_id, response.fragment_id);
480 } else {
481 TransactionResult result;
482 bool continueLoadRequest = false;
483 if (response.success && !transaction.isComplete()) {
484 if (mParent.sendFragmentedLoadNanoAppRequest(transaction) ==
485 Result::OK) {
486 continueLoadRequest = true;
487 result = TransactionResult::SUCCESS;
488 } else {
489 result = TransactionResult::FAILURE;
490 }
491 } else {
492 result = (response.success) ? TransactionResult::SUCCESS
493 : TransactionResult::FAILURE;
494 }
495
496 if (!continueLoadRequest) {
497 mParent.mPendingLoadTransaction.reset();
498 lock.unlock();
499 invokeClientCallback([&]() {
500 return mParent.mCallbacks->handleTxnResult(
501 response.transaction_id, result);
502 });
503 }
504 }
505 }
506 }
507
handleUnloadNanoappResponse(const::chre::fbs::UnloadNanoappResponseT & response)508 void handleUnloadNanoappResponse(
509 const ::chre::fbs::UnloadNanoappResponseT &response) override {
510 ALOGV("Got unload nanoapp response for transaction %" PRIu32
511 " with result %d",
512 response.transaction_id, response.success);
513
514 invokeClientCallback([&]() {
515 TransactionResult result = (response.success)
516 ? TransactionResult::SUCCESS
517 : TransactionResult::FAILURE;
518 return mParent.mCallbacks->handleTxnResult(response.transaction_id,
519 result);
520 });
521 }
522
handleDebugDumpData(const::chre::fbs::DebugDumpDataT & data)523 void handleDebugDumpData(const ::chre::fbs::DebugDumpDataT &data) override {
524 ALOGV("Got debug dump data, size %zu", data.debug_str.size());
525 if (mParent.mDebugFd == kInvalidFd) {
526 ALOGW("Got unexpected debug dump data message");
527 } else {
528 mParent.writeToDebugFile(
529 reinterpret_cast<const char *>(data.debug_str.data()),
530 data.debug_str.size());
531 }
532 }
533
handleDebugDumpResponse(const::chre::fbs::DebugDumpResponseT & response)534 void handleDebugDumpResponse(
535 const ::chre::fbs::DebugDumpResponseT &response) override {
536 ALOGV("Got debug dump response, success %d, data count %" PRIu32,
537 response.success, response.data_count);
538 std::lock_guard<std::mutex> lock(mParent.mDebugDumpMutex);
539 if (!mParent.mDebugDumpPending) {
540 ALOGI("Ignoring duplicate/unsolicited debug dump response");
541 } else {
542 mParent.mDebugDumpPending = false;
543 mParent.mDebugDumpCond.notify_all();
544 }
545 }
546
547 private:
548 GenericContextHubBase &mParent;
549 bool mHaveConnected = false;
550
551 /**
552 * Acquires mParent.mCallbacksLock and invokes the synchronous callback
553 * argument if mParent.mCallbacks is not null.
554 */
invokeClientCallback(std::function<Return<void> ()> callback)555 void invokeClientCallback(std::function<Return<void>()> callback) {
556 std::lock_guard<std::mutex> lock(mParent.mCallbacksLock);
557 if (mParent.mCallbacks != nullptr && !callback().isOk()) {
558 ALOGE("Failed to invoke client callback");
559 }
560 }
561 };
562
563 class DeathRecipient : public hidl_death_recipient {
564 public:
DeathRecipient(const sp<GenericContextHubBase> contexthub)565 explicit DeathRecipient(const sp<GenericContextHubBase> contexthub)
566 : mGenericContextHub(contexthub) {}
serviceDied(uint64_t cookie,const wp<::android::hidl::base::V1_0::IBase> &)567 void serviceDied(
568 uint64_t cookie,
569 const wp<::android::hidl::base::V1_0::IBase> & /* who */) override {
570 uint32_t hubId = static_cast<uint32_t>(cookie);
571 mGenericContextHub->handleServiceDeath(hubId);
572 }
573
574 private:
575 sp<GenericContextHubBase> mGenericContextHub;
576 };
577
578 sp<SocketCallbacks> mSocketCallbacks;
579 sp<DeathRecipient> mDeathRecipient;
580
581 // Cached hub info used for getHubs(), and synchronization primitives to make
582 // that function call synchronous if we need to query it
583 ContextHub mHubInfo;
584 bool mHubInfoValid = false;
585 std::mutex mHubInfoMutex;
586 std::condition_variable mHubInfoCond;
587
588 static constexpr int kInvalidFd = -1;
589 int mDebugFd = kInvalidFd;
590 bool mDebugDumpPending = false;
591 std::mutex mDebugDumpMutex;
592 std::condition_variable mDebugDumpCond;
593
594 // The pending fragmented load request
595 uint32_t mCurrentFragmentId = 0;
596 std::optional<FragmentedLoadTransaction> mPendingLoadTransaction;
597 std::mutex mPendingLoadTransactionMutex;
598
599 // Write a string to mDebugFd
writeToDebugFile(const char * str)600 void writeToDebugFile(const char *str) {
601 writeToDebugFile(str, strlen(str));
602 }
603
writeToDebugFile(const char * str,size_t len)604 void writeToDebugFile(const char *str, size_t len) {
605 ssize_t written = write(mDebugFd, str, len);
606 if (written != (ssize_t)len) {
607 ALOGW(
608 "Couldn't write to debug header: returned %zd, expected %zu (errno "
609 "%d)",
610 written, len, errno);
611 }
612 }
613
614 // Unregisters callback when context hub service dies
handleServiceDeath(uint32_t hubId)615 void handleServiceDeath(uint32_t hubId) {
616 std::lock_guard<std::mutex> lock(mCallbacksLock);
617 ALOGI("Context hub service died for hubId %" PRIu32, hubId);
618 mCallbacks.clear();
619 }
620
621 /**
622 * Checks to see if a load response matches the currently pending
623 * fragmented load transaction. mPendingLoadTransactionMutex must
624 * be acquired prior to calling this function.
625 *
626 * @param response the received load response
627 *
628 * @return true if the response matches a pending load transaction
629 * (if any), false otherwise
630 */
isExpectedLoadResponseLocked(const::chre::fbs::LoadNanoappResponseT & response)631 bool isExpectedLoadResponseLocked(
632 const ::chre::fbs::LoadNanoappResponseT &response) {
633 return mPendingLoadTransaction.has_value() &&
634 (mPendingLoadTransaction->getTransactionId() ==
635 response.transaction_id) &&
636 (response.fragment_id == 0 ||
637 mCurrentFragmentId == response.fragment_id);
638 }
639
640 /**
641 * Sends a fragmented load request to CHRE. The caller must ensure that
642 * transaction.isComplete() returns false prior to invoking this method.
643 *
644 * @param transaction the FragmentedLoadTransaction object
645 *
646 * @return the result of the request
647 */
sendFragmentedLoadNanoAppRequest(FragmentedLoadTransaction & transaction)648 Result sendFragmentedLoadNanoAppRequest(
649 FragmentedLoadTransaction &transaction) {
650 Result result;
651 const FragmentedLoadRequest &request = transaction.getNextRequest();
652
653 FlatBufferBuilder builder(128 + request.binary.size());
654 HostProtocolHost::encodeFragmentedLoadNanoappRequest(builder, request);
655
656 if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
657 ALOGE("Failed to send load request message (fragment ID = %zu)",
658 request.fragmentId);
659 result = Result::UNKNOWN_FAILURE;
660 } else {
661 mCurrentFragmentId = request.fragmentId;
662 result = Result::OK;
663 }
664
665 return result;
666 }
667 };
668
669 } // namespace implementation
670 } // namespace common
671 } // namespace contexthub
672 } // namespace hardware
673 } // namespace android
674
675 #endif // ANDROID_HARDWARE_CONTEXTHUB_COMMON_CONTEXTHUB_H
676