1 /*
2  * Copyright (C) 2022 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 #include "multi_client_context_hub_base.h"
18 
19 #include <chre/platform/shared/host_protocol_common.h>
20 #include <chre_host/generated/host_messages_generated.h>
21 #include <chre_host/log.h>
22 #include "chre/common.h"
23 #include "chre/event.h"
24 #include "chre_host/config_util.h"
25 #include "chre_host/fragmented_load_transaction.h"
26 #include "chre_host/hal_error.h"
27 #include "chre_host/host_protocol_host.h"
28 #include "hal_client_id.h"
29 #include "permissions_util.h"
30 
31 #include <android_chre_flags.h>
32 #include <system/chre/core/chre_metrics.pb.h>
33 #include <chrono>
34 
35 namespace android::hardware::contexthub::common::implementation {
36 
37 using ::android::base::WriteStringToFd;
38 using ::android::chre::FragmentedLoadTransaction;
39 using ::android::chre::getStringFromByteVector;
40 using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
41 using ::android::chre::flags::abort_if_no_context_hub_found;
42 using ::android::chre::flags::bug_fix_hal_reliable_message_record;
43 using ::ndk::ScopedAStatus;
44 namespace fbs = ::chre::fbs;
45 
46 namespace {
47 constexpr uint32_t kDefaultHubId = 0;
48 
49 // timeout for calling getContextHubs(), which is synchronous
50 constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
51 // timeout for enable/disable test mode, which is synchronous
52 constexpr std::chrono::duration ktestModeTimeOut = std::chrono::seconds(5);
53 
54 // The transaction id for synchronously load/unload a nanoapp in test mode.
55 constexpr int32_t kTestModeTransactionId{static_cast<int32_t>(0x80000000)};
56 
57 // Allow build-time override.
58 #ifndef CHRE_NANOAPP_IMAGE_HEADER_SIZE
59 #define CHRE_NANOAPP_IMAGE_HEADER_SIZE (0x1000)
60 #endif
61 constexpr size_t kNanoappImageHeaderSize = CHRE_NANOAPP_IMAGE_HEADER_SIZE;
62 
isValidContextHubId(uint32_t hubId)63 bool isValidContextHubId(uint32_t hubId) {
64   if (hubId != kDefaultHubId) {
65     LOGE("Invalid context hub ID %" PRId32, hubId);
66     return false;
67   }
68   return true;
69 }
70 
getFbsSetting(const Setting & setting,fbs::Setting * fbsSetting)71 bool getFbsSetting(const Setting &setting, fbs::Setting *fbsSetting) {
72   bool foundSetting = true;
73   switch (setting) {
74     case Setting::LOCATION:
75       *fbsSetting = fbs::Setting::LOCATION;
76       break;
77     case Setting::AIRPLANE_MODE:
78       *fbsSetting = fbs::Setting::AIRPLANE_MODE;
79       break;
80     case Setting::MICROPHONE:
81       *fbsSetting = fbs::Setting::MICROPHONE;
82       break;
83     default:
84       foundSetting = false;
85       LOGE("Setting update with invalid enum value %hhu", setting);
86       break;
87   }
88   return foundSetting;
89 }
90 
toFbsSettingState(bool enabled)91 chre::fbs::SettingState toFbsSettingState(bool enabled) {
92   return enabled ? chre::fbs::SettingState::ENABLED
93                  : chre::fbs::SettingState::DISABLED;
94 }
95 
96 // functions that extract different version numbers
extractChreApiMajorVersion(uint32_t chreVersion)97 inline constexpr int8_t extractChreApiMajorVersion(uint32_t chreVersion) {
98   return static_cast<int8_t>(chreVersion >> 24);
99 }
extractChreApiMinorVersion(uint32_t chreVersion)100 inline constexpr int8_t extractChreApiMinorVersion(uint32_t chreVersion) {
101   return static_cast<int8_t>(chreVersion >> 16);
102 }
extractChrePatchVersion(uint32_t chreVersion)103 inline constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
104   return static_cast<uint16_t>(chreVersion);
105 }
106 
107 // functions that help to generate ScopedAStatus from different values.
fromServiceError(HalError errorCode)108 inline ScopedAStatus fromServiceError(HalError errorCode) {
109   return ScopedAStatus::fromServiceSpecificError(
110       static_cast<int32_t>(errorCode));
111 }
fromResult(bool result)112 inline ScopedAStatus fromResult(bool result) {
113   return result ? ScopedAStatus::ok()
114                 : fromServiceError(HalError::OPERATION_FAILED);
115 }
116 
toChreErrorCode(ErrorCode errorCode)117 uint8_t toChreErrorCode(ErrorCode errorCode) {
118   switch (errorCode) {
119     case ErrorCode::OK:
120       return CHRE_ERROR_NONE;
121     case ErrorCode::TRANSIENT_ERROR:
122       return CHRE_ERROR_TRANSIENT;
123     case ErrorCode::PERMANENT_ERROR:
124       return CHRE_ERROR;
125     case ErrorCode::PERMISSION_DENIED:
126       return CHRE_ERROR_PERMISSION_DENIED;
127     case ErrorCode::DESTINATION_NOT_FOUND:
128       return CHRE_ERROR_DESTINATION_NOT_FOUND;
129   }
130 
131   return CHRE_ERROR;
132 }
133 
toErrorCode(uint32_t chreErrorCode)134 ErrorCode toErrorCode(uint32_t chreErrorCode) {
135   switch (chreErrorCode) {
136     case CHRE_ERROR_NONE:
137       return ErrorCode::OK;
138     case CHRE_ERROR_BUSY: // fallthrough
139     case CHRE_ERROR_TRANSIENT:
140       return ErrorCode::TRANSIENT_ERROR;
141     case CHRE_ERROR:
142       return ErrorCode::PERMANENT_ERROR;
143     case CHRE_ERROR_PERMISSION_DENIED:
144       return ErrorCode::PERMISSION_DENIED;
145     case CHRE_ERROR_DESTINATION_NOT_FOUND:
146       return ErrorCode::DESTINATION_NOT_FOUND;
147   }
148 
149   return ErrorCode::PERMANENT_ERROR;
150 }
151 
152 }  // anonymous namespace
153 
MultiClientContextHubBase()154 MultiClientContextHubBase::MultiClientContextHubBase() {
155   mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
156       AIBinder_DeathRecipient_new(onClientDied));
157   AIBinder_DeathRecipient_setOnUnlinked(
158       mDeathRecipient.get(), /*onUnlinked= */ [](void *cookie) {
159         LOGI("Callback is unlinked. Releasing the death recipient cookie.");
160         delete static_cast<HalDeathRecipientCookie *>(cookie);
161       });
162   mDeadClientUnlinker =
163       [&deathRecipient = mDeathRecipient](
164           const std::shared_ptr<IContextHubCallback> &callback,
165           void *deathRecipientCookie) {
166         return AIBinder_unlinkToDeath(callback->asBinder().get(),
167                                       deathRecipient.get(),
168                                       deathRecipientCookie) == STATUS_OK;
169       };
170   mLogger.init(kNanoappImageHeaderSize);
171 }
172 
getContextHubs(std::vector<ContextHubInfo> * contextHubInfos)173 ScopedAStatus MultiClientContextHubBase::getContextHubs(
174     std::vector<ContextHubInfo> *contextHubInfos) {
175   if (!mIsChreReady) {
176     LOGE("%s() can't be processed as CHRE is not ready", __func__);
177     // Return ok() here to not crash system server
178     return ScopedAStatus::ok();
179   }
180 
181   std::unique_lock<std::mutex> lock(mHubInfoMutex);
182   if (mContextHubInfo == nullptr) {
183     fbs::HubInfoResponseT response;
184     flatbuffers::FlatBufferBuilder builder;
185     HostProtocolHost::encodeHubInfoRequest(builder);
186     if (mConnection->sendMessage(builder)) {
187       mHubInfoCondition.wait_for(lock, kHubInfoQueryTimeout, [this]() {
188         return mContextHubInfo != nullptr;
189       });
190     } else {
191       LOGE("Failed to send a message to CHRE to get context hub info.");
192     }
193   }
194   if (mContextHubInfo != nullptr) {
195     contextHubInfos->push_back(*mContextHubInfo);
196   } else {
197     LOGE("Unable to get a valid context hub info for PID %d",
198          AIBinder_getCallingPid());
199     if (abort_if_no_context_hub_found()) {
200       std::abort();
201     }
202   }
203   return ScopedAStatus::ok();
204 }
205 
loadNanoapp(int32_t contextHubId,const NanoappBinary & appBinary,int32_t transactionId)206 ScopedAStatus MultiClientContextHubBase::loadNanoapp(
207     int32_t contextHubId, const NanoappBinary &appBinary,
208     int32_t transactionId) {
209   if (!mIsChreReady) {
210     LOGE("%s() can't be processed as CHRE is not ready", __func__);
211     return fromServiceError(HalError::CHRE_NOT_READY);
212   }
213   if (!isValidContextHubId(contextHubId)) {
214     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
215   }
216   LOGD("Loading nanoapp 0x%" PRIx64 ", transaction id=%" PRIi32,
217        appBinary.nanoappId, transactionId);
218   uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
219                               (appBinary.targetChreApiMinorVersion << 16);
220   auto nanoappBuffer =
221       std::make_shared<std::vector<uint8_t>>(appBinary.customBinary);
222   mLogger.onNanoappLoadStarted(appBinary.nanoappId, nanoappBuffer);
223   auto transaction = std::make_unique<FragmentedLoadTransaction>(
224       transactionId, appBinary.nanoappId, appBinary.nanoappVersion,
225       appBinary.flags, targetApiVersion, appBinary.customBinary,
226       mConnection->getLoadFragmentSizeBytes());
227   pid_t pid = AIBinder_getCallingPid();
228   if (!mHalClientManager->registerPendingLoadTransaction(
229           pid, std::move(transaction))) {
230     return fromResult(false);
231   }
232 
233   HalClientId clientId = mHalClientManager->getClientId(pid);
234   std::optional<chre::FragmentedLoadRequest> request =
235       mHalClientManager->getNextFragmentedLoadRequest();
236   if (!request.has_value()) {
237     return fromResult(false);
238   }
239 
240   if (sendFragmentedLoadRequest(clientId, request.value())) {
241     return ScopedAStatus::ok();
242   }
243   LOGE("Failed to send the first load request for nanoapp 0x%" PRIx64,
244        appBinary.nanoappId);
245   mHalClientManager->resetPendingLoadTransaction();
246   mLogger.onNanoappLoadFailed(appBinary.nanoappId);
247   if (mMetricsReporter != nullptr) {
248     mMetricsReporter->logNanoappLoadFailed(
249         appBinary.nanoappId, ChreHalNanoappLoadFailed::Type::TYPE_DYNAMIC,
250         ChreHalNanoappLoadFailed::Reason::REASON_CONNECTION_ERROR);
251   }
252   return fromResult(false);
253 }
254 
sendFragmentedLoadRequest(HalClientId clientId,FragmentedLoadRequest & request)255 bool MultiClientContextHubBase::sendFragmentedLoadRequest(
256     HalClientId clientId, FragmentedLoadRequest &request) {
257   flatbuffers::FlatBufferBuilder builder(128 + request.binary.size());
258   HostProtocolHost::encodeFragmentedLoadNanoappRequest(
259       builder, request, /* respondBeforeStart= */ false);
260   HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
261                                        builder.GetSize(), clientId);
262   return mConnection->sendMessage(builder);
263 }
264 
unloadNanoapp(int32_t contextHubId,int64_t appId,int32_t transactionId)265 ScopedAStatus MultiClientContextHubBase::unloadNanoapp(int32_t contextHubId,
266                                                        int64_t appId,
267                                                        int32_t transactionId) {
268   if (!mIsChreReady) {
269     LOGE("%s() can't be processed as CHRE is not ready", __func__);
270     return fromServiceError(HalError::CHRE_NOT_READY);
271   }
272   if (!isValidContextHubId(contextHubId)) {
273     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
274   }
275   pid_t pid = AIBinder_getCallingPid();
276   if (transactionId != kTestModeTransactionId &&
277       !mHalClientManager->registerPendingUnloadTransaction(pid, transactionId,
278                                                            appId)) {
279     return fromResult(false);
280   }
281   LOGD("Unloading nanoapp 0x%" PRIx64, appId);
282   HalClientId clientId = mHalClientManager->getClientId(pid);
283   flatbuffers::FlatBufferBuilder builder(64);
284   HostProtocolHost::encodeUnloadNanoappRequest(
285       builder, transactionId, appId, /* allowSystemNanoappUnload= */ false);
286   HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
287                                        builder.GetSize(), clientId);
288 
289   bool result = mConnection->sendMessage(builder);
290   if (!result) {
291     LOGE("Failed to send an unload request for nanoapp 0x%" PRIx64
292          " transaction %" PRIi32,
293          appId, transactionId);
294     mHalClientManager->resetPendingUnloadTransaction(clientId, transactionId);
295   }
296   return fromResult(result);
297 }
298 
disableNanoapp(int32_t,int64_t appId,int32_t)299 ScopedAStatus MultiClientContextHubBase::disableNanoapp(
300     int32_t /* contextHubId */, int64_t appId, int32_t /* transactionId */) {
301   LOGW("Attempted to disable app ID 0x%016" PRIx64 ", but not supported",
302        appId);
303   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
304 }
305 
enableNanoapp(int32_t,int64_t appId,int32_t)306 ScopedAStatus MultiClientContextHubBase::enableNanoapp(
307     int32_t /* contextHubId */, int64_t appId, int32_t /* transactionId */) {
308   LOGW("Attempted to enable app ID 0x%016" PRIx64 ", but not supported", appId);
309   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
310 }
311 
onSettingChanged(Setting setting,bool enabled)312 ScopedAStatus MultiClientContextHubBase::onSettingChanged(Setting setting,
313                                                           bool enabled) {
314   if (!mIsChreReady) {
315     LOGE("%s() can't be processed as CHRE is not ready", __func__);
316     return fromServiceError(HalError::CHRE_NOT_READY);
317   }
318   mSettingEnabled[setting] = enabled;
319   fbs::Setting fbsSetting;
320   bool isWifiOrBtSetting =
321       (setting == Setting::WIFI_MAIN || setting == Setting::WIFI_SCANNING ||
322        setting == Setting::BT_MAIN || setting == Setting::BT_SCANNING);
323   if (!isWifiOrBtSetting && getFbsSetting(setting, &fbsSetting)) {
324     flatbuffers::FlatBufferBuilder builder(64);
325     HostProtocolHost::encodeSettingChangeNotification(
326         builder, fbsSetting, toFbsSettingState(enabled));
327     mConnection->sendMessage(builder);
328   }
329 
330   bool isWifiMainEnabled = isSettingEnabled(Setting::WIFI_MAIN);
331   bool isWifiScanEnabled = isSettingEnabled(Setting::WIFI_SCANNING);
332   bool isAirplaneModeEnabled = isSettingEnabled(Setting::AIRPLANE_MODE);
333 
334   // Because the airplane mode impact on WiFi is not standardized in Android,
335   // we write a specific handling in the Context Hub HAL to inform CHRE.
336   // The following definition is a default one, and can be adjusted
337   // appropriately if necessary.
338   bool isWifiAvailable = isAirplaneModeEnabled
339                              ? (isWifiMainEnabled)
340                              : (isWifiMainEnabled || isWifiScanEnabled);
341   if (!mIsWifiAvailable.has_value() || (isWifiAvailable != mIsWifiAvailable)) {
342     flatbuffers::FlatBufferBuilder builder(64);
343     HostProtocolHost::encodeSettingChangeNotification(
344         builder, fbs::Setting::WIFI_AVAILABLE,
345         toFbsSettingState(isWifiAvailable));
346     mConnection->sendMessage(builder);
347     mIsWifiAvailable = isWifiAvailable;
348   }
349 
350   // The BT switches determine whether we can BLE scan which is why things are
351   // mapped like this into CHRE.
352   bool isBtMainEnabled = isSettingEnabled(Setting::BT_MAIN);
353   bool isBtScanEnabled = isSettingEnabled(Setting::BT_SCANNING);
354   bool isBleAvailable = isBtMainEnabled || isBtScanEnabled;
355   if (!mIsBleAvailable.has_value() || (isBleAvailable != mIsBleAvailable)) {
356     flatbuffers::FlatBufferBuilder builder(64);
357     HostProtocolHost::encodeSettingChangeNotification(
358         builder, fbs::Setting::BLE_AVAILABLE,
359         toFbsSettingState(isBleAvailable));
360     mConnection->sendMessage(builder);
361     mIsBleAvailable = isBleAvailable;
362   }
363 
364   return ScopedAStatus::ok();
365 }
366 
queryNanoapps(int32_t contextHubId)367 ScopedAStatus MultiClientContextHubBase::queryNanoapps(int32_t contextHubId) {
368   return queryNanoappsWithClientId(
369       contextHubId, mHalClientManager->getClientId(AIBinder_getCallingPid()));
370 }
371 
getPreloadedNanoappIds(int32_t contextHubId,std::vector<int64_t> * out_preloadedNanoappIds)372 ScopedAStatus MultiClientContextHubBase::getPreloadedNanoappIds(
373     int32_t contextHubId, std::vector<int64_t> *out_preloadedNanoappIds) {
374   if (contextHubId != kDefaultHubId) {
375     LOGE("Invalid ID %" PRId32, contextHubId);
376     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
377   }
378   if (out_preloadedNanoappIds == nullptr) {
379     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
380   }
381   std::unique_lock<std::mutex> lock(mPreloadedNanoappIdsMutex);
382   if (!mPreloadedNanoappIds.has_value()) {
383     mPreloadedNanoappIds = std::vector<uint64_t>{};
384     mPreloadedNanoappLoader->getPreloadedNanoappIds(*mPreloadedNanoappIds);
385   }
386   for (const auto &nanoappId : mPreloadedNanoappIds.value()) {
387     out_preloadedNanoappIds->emplace_back(static_cast<uint64_t>(nanoappId));
388   }
389   return ScopedAStatus::ok();
390 }
391 
registerCallback(int32_t contextHubId,const std::shared_ptr<IContextHubCallback> & callback)392 ScopedAStatus MultiClientContextHubBase::registerCallback(
393     int32_t contextHubId,
394     const std::shared_ptr<IContextHubCallback> &callback) {
395   // Even CHRE is not ready we should open this API to clients because it allows
396   // us to have a channel to report events back to them.
397   if (!isValidContextHubId(contextHubId)) {
398     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
399   }
400   if (callback == nullptr) {
401     LOGE("Callback of context hub HAL must not be null");
402     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
403   }
404   pid_t pid = AIBinder_getCallingPid();
405   auto *cookie = new HalDeathRecipientCookie(this, pid);
406   if (AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(),
407                            cookie) != STATUS_OK) {
408     LOGE("Failed to link a client binder (pid=%d) to the death recipient", pid);
409     delete cookie;
410     return fromResult(false);
411   }
412   // If AIBinder_linkToDeath is successful the cookie will be released by the
413   // callback of binder unlinking (callback overridden).
414   if (!mHalClientManager->registerCallback(pid, callback, cookie)) {
415     LOGE("Unable to register a client (pid=%d) callback", pid);
416     return fromResult(false);
417   }
418   return ScopedAStatus::ok();
419 }
420 
sendMessageToHub(int32_t contextHubId,const ContextHubMessage & message)421 ScopedAStatus MultiClientContextHubBase::sendMessageToHub(
422     int32_t contextHubId, const ContextHubMessage &message) {
423   if (!mIsChreReady) {
424     LOGE("%s() can't be processed as CHRE is not ready", __func__);
425     return fromServiceError(HalError::CHRE_NOT_READY);
426   }
427   if (!isValidContextHubId(contextHubId)) {
428     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
429   }
430 
431   HostEndpointId hostEndpointId = message.hostEndPoint;
432   if (!mHalClientManager->mutateEndpointIdFromHostIfNeeded(
433           AIBinder_getCallingPid(), hostEndpointId)) {
434     return fromResult(false);
435   }
436 
437   if (message.isReliable) {
438     if (bug_fix_hal_reliable_message_record()) {
439       std::lock_guard<std::mutex> lock(mReliableMessageMutex);
440       auto iter = std::find_if(
441           mReliableMessageQueue.begin(), mReliableMessageQueue.end(),
442           [&message](const ReliableMessageRecord &record) {
443             return record.messageSequenceNumber == message.messageSequenceNumber;
444           });
445       if (iter == mReliableMessageQueue.end()) {
446         mReliableMessageQueue.push_back(ReliableMessageRecord{
447             .timestamp = std::chrono::steady_clock::now(),
448             .messageSequenceNumber = message.messageSequenceNumber,
449             .hostEndpointId = hostEndpointId});
450         std::push_heap(mReliableMessageQueue.begin(), mReliableMessageQueue.end(),
451                       std::greater<ReliableMessageRecord>());
452       }
453       cleanupReliableMessageQueueLocked();
454     } else {
455       mReliableMessageMap.insert({message.messageSequenceNumber, hostEndpointId});
456     }
457   }
458 
459   flatbuffers::FlatBufferBuilder builder(1024);
460   HostProtocolHost::encodeNanoappMessage(
461       builder, message.nanoappId, message.messageType, hostEndpointId,
462       message.messageBody.data(), message.messageBody.size(),
463       /* permissions= */ 0,
464       /* messagePermissions= */ 0,
465       /* wokeHost= */ false, message.isReliable, message.messageSequenceNumber);
466 
467   bool success = mConnection->sendMessage(builder);
468   mEventLogger.logMessageToNanoapp(message, success);
469   return fromResult(success);
470 }
471 
onHostEndpointConnected(const HostEndpointInfo & info)472 ScopedAStatus MultiClientContextHubBase::onHostEndpointConnected(
473     const HostEndpointInfo &info) {
474   if (!mIsChreReady) {
475     LOGE("%s() can't be processed as CHRE is not ready", __func__);
476     return fromServiceError(HalError::CHRE_NOT_READY);
477   }
478   uint8_t type;
479   switch (info.type) {
480     case HostEndpointInfo::Type::APP:
481       type = CHRE_HOST_ENDPOINT_TYPE_APP;
482       break;
483     case HostEndpointInfo::Type::NATIVE:
484       type = CHRE_HOST_ENDPOINT_TYPE_NATIVE;
485       break;
486     case HostEndpointInfo::Type::FRAMEWORK:
487       type = CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK;
488       break;
489     default:
490       LOGE("Unsupported host endpoint type %" PRIu32, info.type);
491       return fromServiceError(HalError::INVALID_ARGUMENT);
492   }
493 
494   uint16_t endpointId = info.hostEndpointId;
495   pid_t pid = AIBinder_getCallingPid();
496   if (!mHalClientManager->registerEndpointId(pid, info.hostEndpointId) ||
497       !mHalClientManager->mutateEndpointIdFromHostIfNeeded(pid, endpointId)) {
498     return fromServiceError(HalError::INVALID_ARGUMENT);
499   }
500   flatbuffers::FlatBufferBuilder builder(64);
501   HostProtocolHost::encodeHostEndpointConnected(
502       builder, endpointId, type, info.packageName.value_or(std::string()),
503       info.attributionTag.value_or(std::string()));
504   return fromResult(mConnection->sendMessage(builder));
505 }
506 
onHostEndpointDisconnected(char16_t in_hostEndpointId)507 ScopedAStatus MultiClientContextHubBase::onHostEndpointDisconnected(
508     char16_t in_hostEndpointId) {
509   if (!mIsChreReady) {
510     LOGE("%s() can't be processed as CHRE is not ready", __func__);
511     return fromServiceError(HalError::CHRE_NOT_READY);
512   }
513   HostEndpointId hostEndpointId = in_hostEndpointId;
514   pid_t pid = AIBinder_getCallingPid();
515   bool isSuccessful = false;
516   if (mHalClientManager->removeEndpointId(pid, hostEndpointId) &&
517       mHalClientManager->mutateEndpointIdFromHostIfNeeded(pid,
518                                                           hostEndpointId)) {
519     flatbuffers::FlatBufferBuilder builder(64);
520     HostProtocolHost::encodeHostEndpointDisconnected(builder, hostEndpointId);
521     isSuccessful = mConnection->sendMessage(builder);
522   }
523   if (!isSuccessful) {
524     LOGW("Unable to remove host endpoint id %" PRIu16, in_hostEndpointId);
525   }
526   return ScopedAStatus::ok();
527 }
528 
onNanSessionStateChanged(const NanSessionStateUpdate &)529 ScopedAStatus MultiClientContextHubBase::onNanSessionStateChanged(
530     const NanSessionStateUpdate & /*in_update*/) {
531   if (!mIsChreReady) {
532     LOGE("%s() can't be processed as CHRE is not ready", __func__);
533     return fromServiceError(HalError::CHRE_NOT_READY);
534   }
535   // TODO(271471342): Add support for NAN session management.
536   return ndk::ScopedAStatus::ok();
537 }
538 
setTestMode(bool enable)539 ScopedAStatus MultiClientContextHubBase::setTestMode(bool enable) {
540   if (!mIsChreReady) {
541     LOGE("%s() can't be processed as CHRE is not ready", __func__);
542     return fromServiceError(HalError::CHRE_NOT_READY);
543   }
544   if (enable) {
545     return fromResult(enableTestMode());
546   }
547   disableTestMode();
548   return ScopedAStatus::ok();
549 }
550 
sendMessageDeliveryStatusToHub(int32_t contextHubId,const MessageDeliveryStatus & messageDeliveryStatus)551 ScopedAStatus MultiClientContextHubBase::sendMessageDeliveryStatusToHub(
552     int32_t contextHubId, const MessageDeliveryStatus &messageDeliveryStatus) {
553   if (!mIsChreReady) {
554     LOGE("%s() can't be processed as CHRE is not ready", __func__);
555     return fromServiceError(HalError::CHRE_NOT_READY);
556   }
557   if (!isValidContextHubId(contextHubId)) {
558     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
559   }
560 
561   flatbuffers::FlatBufferBuilder builder(64);
562   HostProtocolHost::encodeMessageDeliveryStatus(
563       builder, messageDeliveryStatus.messageSequenceNumber,
564       toChreErrorCode(messageDeliveryStatus.errorCode));
565 
566   bool success = mConnection->sendMessage(builder);
567   if (!success) {
568     LOGE("Failed to send a message delivery status to CHRE");
569   }
570   return fromResult(success);
571 }
572 
getHubs(std::vector<HubInfo> * hubs)573 ScopedAStatus MultiClientContextHubBase::getHubs(std::vector<HubInfo> *hubs) {
574   if (mV4Impl) return mV4Impl->getHubs(hubs);
575   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
576 }
577 
getEndpoints(std::vector<EndpointInfo> * endpoints)578 ScopedAStatus MultiClientContextHubBase::getEndpoints(
579     std::vector<EndpointInfo> *endpoints) {
580   if (mV4Impl) return mV4Impl->getEndpoints(endpoints);
581   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
582 }
583 
registerEndpointHub(const std::shared_ptr<IEndpointCallback> & callback,const HubInfo & hubInfo,std::shared_ptr<IEndpointCommunication> * hubInterface)584 ScopedAStatus MultiClientContextHubBase::registerEndpointHub(
585     const std::shared_ptr<IEndpointCallback> &callback, const HubInfo &hubInfo,
586     std::shared_ptr<IEndpointCommunication> *hubInterface) {
587   if (mV4Impl)
588     return mV4Impl->registerEndpointHub(callback, hubInfo, hubInterface);
589   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
590 }
591 
enableTestModeLocked(std::unique_lock<std::mutex> & lock)592 bool MultiClientContextHubBase::enableTestModeLocked(
593     std::unique_lock<std::mutex> &lock) {
594   // Pulling out a list of loaded nanoapps.
595   mTestModeNanoapps.reset();
596   mTestModeSystemNanoapps.reset();
597   if (!queryNanoappsWithClientId(kDefaultHubId, kHalId).isOk()) {
598     LOGE("Failed to get a list of loaded nanoapps to enable test mode");
599     return false;
600   }
601   if (!mEnableTestModeCv.wait_for(lock, ktestModeTimeOut, [&]() {
602         return mTestModeNanoapps.has_value() &&
603                mTestModeSystemNanoapps.has_value();
604       })) {
605     LOGE("Failed to get a list of loaded nanoapps within %" PRIu64
606          " seconds to enable test mode",
607          ktestModeTimeOut.count());
608     return false;
609   }
610 
611   // Unload each nanoapp.
612   // mTestModeNanoapps tracks nanoapps that are actually unloaded. Removing an
613   // element from std::vector is O(n) but such a removal should rarely happen.
614   LOGD("Trying to unload %" PRIu64 " nanoapps to enable test mode",
615        mTestModeNanoapps->size());
616   for (auto iter = mTestModeNanoapps->begin();
617        iter != mTestModeNanoapps->end();) {
618     auto appId = static_cast<int64_t>(*iter);
619 
620     // Send a request to unload a nanoapp.
621     if (!unloadNanoapp(kDefaultHubId, appId, kTestModeTransactionId).isOk()) {
622       LOGW("Failed to request to unload nanoapp 0x%" PRIx64
623            " to enable test mode",
624            appId);
625       iter = mTestModeNanoapps->erase(iter);
626       continue;
627     }
628 
629     // Wait for the unloading result.
630     mTestModeSyncUnloadResult.reset();
631     mEnableTestModeCv.wait_for(lock, ktestModeTimeOut, [&]() {
632       return mTestModeSyncUnloadResult.has_value();
633     });
634     bool success =
635         mTestModeSyncUnloadResult.has_value() && *mTestModeSyncUnloadResult;
636     if (success) {
637       iter++;
638     } else {
639       LOGW("Failed to unload nanoapp 0x%" PRIx64 " to enable test mode", appId);
640       iter = mTestModeNanoapps->erase(iter);
641     }
642     mEventLogger.logNanoappUnload(appId, success);
643   }
644 
645   LOGD("%" PRIu64 " nanoapps are unloaded to enable test mode",
646        mTestModeNanoapps->size());
647   return true;
648 }
649 
enableTestMode()650 bool MultiClientContextHubBase::enableTestMode() {
651   std::unique_lock<std::mutex> lock(mTestModeMutex);
652   if (mIsTestModeEnabled) {
653     return true;
654   }
655   // Needed to ensure multiple calls to enableTestMode to not race as we unlock
656   // the lock to query the nanoapps.
657   mIsTestModeEnabled = true;
658 
659   mIsTestModeEnabled = enableTestModeLocked(lock);
660   return mIsTestModeEnabled;
661 }
662 
disableTestMode()663 void MultiClientContextHubBase::disableTestMode() {
664   std::unique_lock<std::mutex> lock(mTestModeMutex);
665   if (!mIsTestModeEnabled) {
666     return;
667   }
668 
669   mIsTestModeEnabled = false;
670   int numOfNanoappsLoaded =
671       mPreloadedNanoappLoader->loadPreloadedNanoapps(mTestModeSystemNanoapps);
672   LOGD("%d nanoapps are reloaded to recover from test mode",
673        numOfNanoappsLoaded);
674 }
675 
queryNanoappsWithClientId(int32_t contextHubId,HalClientId clientId)676 ScopedAStatus MultiClientContextHubBase::queryNanoappsWithClientId(
677     int32_t contextHubId, HalClientId clientId) {
678   if (!mIsChreReady) {
679     LOGE("%s() can't be processed as CHRE is not ready", __func__);
680     return fromServiceError(HalError::CHRE_NOT_READY);
681   }
682   if (!isValidContextHubId(contextHubId)) {
683     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
684   }
685   flatbuffers::FlatBufferBuilder builder(64);
686   HostProtocolHost::encodeNanoappListRequest(builder);
687   HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
688                                        builder.GetSize(), clientId);
689   return fromResult(mConnection->sendMessage(builder));
690 }
691 
handleTestModeNanoappQueryResponse(const::chre::fbs::NanoappListResponseT & response)692 void MultiClientContextHubBase::handleTestModeNanoappQueryResponse(
693     const ::chre::fbs::NanoappListResponseT &response) {
694   {
695     std::unique_lock<std::mutex> lock(mTestModeMutex);
696     mTestModeNanoapps.emplace();
697     mTestModeSystemNanoapps.emplace();
698 
699     for (const auto &nanoapp : response.nanoapps) {
700       if (nanoapp->is_system) {
701         mTestModeSystemNanoapps->push_back(nanoapp->app_id);
702       } else {
703         mTestModeNanoapps->push_back(nanoapp->app_id);
704       }
705     }
706   }
707 
708   mEnableTestModeCv.notify_all();
709 }
710 
handleMessageFromChre(const unsigned char * messageBuffer,size_t messageLen)711 void MultiClientContextHubBase::handleMessageFromChre(
712     const unsigned char *messageBuffer, size_t messageLen) {
713   if (!::chre::HostProtocolCommon::verifyMessage(messageBuffer, messageLen)) {
714     LOGE("Invalid message received from CHRE.");
715     return;
716   }
717   std::unique_ptr<fbs::MessageContainerT> container =
718       fbs::UnPackMessageContainer(messageBuffer);
719   fbs::ChreMessageUnion &message = container->message;
720   HalClientId clientId = container->host_addr->client_id();
721 
722   switch (container->message.type) {
723     case fbs::ChreMessage::HubInfoResponse: {
724       handleHubInfoResponse(*message.AsHubInfoResponse());
725       break;
726     }
727     case fbs::ChreMessage::NanoappListResponse: {
728       onNanoappListResponse(*message.AsNanoappListResponse(), clientId);
729       break;
730     }
731     case fbs::ChreMessage::LoadNanoappResponse: {
732       onNanoappLoadResponse(*message.AsLoadNanoappResponse(), clientId);
733       break;
734     }
735     case fbs::ChreMessage::TimeSyncRequest: {
736       if (mConnection->isTimeSyncNeeded()) {
737         TimeSyncer::sendTimeSync(mConnection.get());
738       } else {
739         LOGW("Received an unexpected time sync request from CHRE.");
740       }
741       break;
742     }
743     case fbs::ChreMessage::UnloadNanoappResponse: {
744       onNanoappUnloadResponse(*message.AsUnloadNanoappResponse(), clientId);
745       break;
746     }
747     case fbs::ChreMessage::NanoappMessage: {
748       onNanoappMessage(*message.AsNanoappMessage());
749       break;
750     }
751     case fbs::ChreMessage::MessageDeliveryStatus: {
752       onMessageDeliveryStatus(*message.AsMessageDeliveryStatus());
753       break;
754     }
755     case fbs::ChreMessage::DebugDumpData: {
756       onDebugDumpData(*message.AsDebugDumpData());
757       break;
758     }
759     case fbs::ChreMessage::DebugDumpResponse: {
760       onDebugDumpComplete(*message.AsDebugDumpResponse());
761       break;
762     }
763     case fbs::ChreMessage::LogMessageV2: {
764       handleLogMessageV2(*message.AsLogMessageV2());
765       break;
766     }
767     case fbs::ChreMessage::MetricLog: {
768       onMetricLog(*message.AsMetricLog());
769       break;
770     }
771     case fbs::ChreMessage::NanoappTokenDatabaseInfo: {
772       const auto *info = message.AsNanoappTokenDatabaseInfo();
773       mLogger.addNanoappDetokenizer(info->app_id, info->instance_id,
774                                     info->database_offset_bytes,
775                                     info->database_size_bytes);
776       break;
777     }
778     default:
779       if (mV4Impl) {
780         mV4Impl->handleMessageFromChre(message);
781       } else {
782         LOGW("Got unexpected message type %" PRIu8,
783              static_cast<uint8_t>(message.type));
784       }
785   }
786 }
787 
handleHubInfoResponse(const fbs::HubInfoResponseT & response)788 void MultiClientContextHubBase::handleHubInfoResponse(
789     const fbs::HubInfoResponseT &response) {
790   std::unique_lock<std::mutex> lock(mHubInfoMutex);
791   mContextHubInfo = std::make_unique<ContextHubInfo>();
792   mContextHubInfo->name = getStringFromByteVector(response.name);
793   mContextHubInfo->vendor = getStringFromByteVector(response.vendor);
794   mContextHubInfo->toolchain = getStringFromByteVector(response.toolchain);
795   mContextHubInfo->id = kDefaultHubId;
796   mContextHubInfo->peakMips = response.peak_mips;
797   mContextHubInfo->maxSupportedMessageLengthBytes = response.max_msg_len;
798   mContextHubInfo->chrePlatformId = response.platform_id;
799   uint32_t version = response.chre_platform_version;
800   mContextHubInfo->chreApiMajorVersion = extractChreApiMajorVersion(version);
801   mContextHubInfo->chreApiMinorVersion = extractChreApiMinorVersion(version);
802   mContextHubInfo->chrePatchVersion = extractChrePatchVersion(version);
803   mContextHubInfo->supportedPermissions = kSupportedPermissions;
804 
805   mContextHubInfo->supportsReliableMessages =
806       response.supports_reliable_messages;
807 
808   mHubInfoCondition.notify_all();
809 }
810 
onDebugDumpData(const::chre::fbs::DebugDumpDataT & data)811 void MultiClientContextHubBase::onDebugDumpData(
812     const ::chre::fbs::DebugDumpDataT &data) {
813   auto str = std::string(reinterpret_cast<const char *>(data.debug_str.data()),
814                          data.debug_str.size());
815   debugDumpAppend(str);
816 }
817 
onDebugDumpComplete(const::chre::fbs::DebugDumpResponseT & response)818 void MultiClientContextHubBase::onDebugDumpComplete(
819     const ::chre::fbs::DebugDumpResponseT &response) {
820   if (!response.success) {
821     LOGE("Dumping debug information fails");
822   }
823   if (checkDebugFd()) {
824     const std::string &dump = mEventLogger.dump();
825     writeToDebugFile(dump.c_str());
826     writeToDebugFile("\n-- End of CHRE/ASH debug info --\n");
827   }
828   debugDumpComplete();
829 }
830 
onNanoappListResponse(const fbs::NanoappListResponseT & response,HalClientId clientId)831 void MultiClientContextHubBase::onNanoappListResponse(
832     const fbs::NanoappListResponseT &response, HalClientId clientId) {
833   LOGD("Received a nanoapp list response for client %" PRIu16, clientId);
834 
835   if (clientId == kHalId) {
836     LOGD("Received a nanoapp list response to enable test mode");
837     handleTestModeNanoappQueryResponse(response);
838     return;  // this query was for test mode -> do not call callback
839   }
840 
841   std::shared_ptr<IContextHubCallback> callback =
842       mHalClientManager->getCallback(clientId);
843   if (callback == nullptr) {
844     return;
845   }
846 
847   std::vector<NanoappInfo> appInfoList;
848   for (const auto &nanoapp : response.nanoapps) {
849     if (nanoapp->is_system) {
850       continue;
851     }
852     NanoappInfo appInfo;
853     appInfo.nanoappId = nanoapp->app_id;
854     appInfo.nanoappVersion = nanoapp->version;
855     appInfo.enabled = nanoapp->enabled;
856     appInfo.permissions = chreToAndroidPermissions(nanoapp->permissions);
857 
858     std::vector<NanoappRpcService> rpcServices;
859     for (const auto &service : nanoapp->rpc_services) {
860       NanoappRpcService aidlService;
861       aidlService.id = service->id;
862       aidlService.version = service->version;
863       rpcServices.emplace_back(aidlService);
864     }
865     appInfo.rpcServices = rpcServices;
866     appInfoList.push_back(appInfo);
867   }
868 
869   callback->handleNanoappInfo(appInfoList);
870 }
871 
onNanoappLoadResponse(const fbs::LoadNanoappResponseT & response,HalClientId clientId)872 void MultiClientContextHubBase::onNanoappLoadResponse(
873     const fbs::LoadNanoappResponseT &response, HalClientId clientId) {
874   LOGV("Received nanoapp load response for client %" PRIu16
875        " transaction %" PRIu32 " fragment %" PRIu32,
876        clientId, response.transaction_id, response.fragment_id);
877   if (mPreloadedNanoappLoader->isPreloadOngoing()) {
878     mPreloadedNanoappLoader->onLoadNanoappResponse(response, clientId);
879     return;
880   }
881 
882   std::optional<HalClientManager::PendingLoadNanoappInfo> nanoappInfo =
883       mHalClientManager->getNanoappInfoFromPendingLoadTransaction(
884           clientId, response.transaction_id, response.fragment_id);
885 
886   if (!nanoappInfo.has_value()) {
887     LOGW("Client %" PRIu16 " transaction %" PRIu32 " fragment %" PRIu32
888          " doesn't have a pending load transaction. Skipped",
889          clientId, response.transaction_id, response.fragment_id);
890     return;
891   }
892 
893   bool success = response.success;
894   auto failureReason = ChreHalNanoappLoadFailed::Reason::REASON_ERROR_GENERIC;
895   if (response.success) {
896     std::optional<chre::FragmentedLoadRequest> nextFragmentedRequest =
897         mHalClientManager->getNextFragmentedLoadRequest();
898     if (nextFragmentedRequest.has_value()) {
899       // nextFragmentedRequest will only have a value if the pending transaction
900       // matches the response and there are more fragments to send. Hold off on
901       // calling the callback in this case.
902       LOGV("Sending next FragmentedLoadRequest for client %" PRIu16
903            ": (transaction: %" PRIu32 ", fragment %zu)",
904            clientId, nextFragmentedRequest->transactionId,
905            nextFragmentedRequest->fragmentId);
906       if (sendFragmentedLoadRequest(clientId, nextFragmentedRequest.value())) {
907         return;
908       }
909       failureReason = ChreHalNanoappLoadFailed::Reason::REASON_CONNECTION_ERROR;
910       success = false;
911     }
912   }
913 
914   // At this moment the current pending transaction should either have no more
915   // fragment to send or the response indicates its last nanoapp fragment fails
916   // to get loaded.
917   if (!success) {
918     LOGE("Loading nanoapp fragment for client %" PRIu16 " transaction %" PRIu32
919          " fragment %" PRIu32 " failed",
920          clientId, response.transaction_id, response.fragment_id);
921     mHalClientManager->resetPendingLoadTransaction();
922     mLogger.onNanoappLoadFailed(nanoappInfo->appId);
923     if (mMetricsReporter != nullptr) {
924       mMetricsReporter->logNanoappLoadFailed(
925           nanoappInfo->appId, ChreHalNanoappLoadFailed::Type::TYPE_DYNAMIC,
926           failureReason);
927     }
928   }
929   mEventLogger.logNanoappLoad(nanoappInfo->appId, nanoappInfo->appSize,
930                               nanoappInfo->appVersion, success);
931   if (auto callback = mHalClientManager->getCallback(clientId);
932       callback != nullptr) {
933     callback->handleTransactionResult(response.transaction_id,
934                                       /* in_success= */ success);
935   }
936 }
937 
onNanoappUnloadResponse(const fbs::UnloadNanoappResponseT & response,HalClientId clientId)938 void MultiClientContextHubBase::onNanoappUnloadResponse(
939     const fbs::UnloadNanoappResponseT &response, HalClientId clientId) {
940   if (response.transaction_id == kTestModeTransactionId) {
941     std::unique_lock<std::mutex> lock(mTestModeMutex);
942     mTestModeSyncUnloadResult.emplace(response.success);
943     mEnableTestModeCv.notify_all();
944     return;
945   }
946 
947   std::optional<int64_t> nanoappId =
948       mHalClientManager->resetPendingUnloadTransaction(clientId,
949                                                        response.transaction_id);
950   if (nanoappId.has_value()) {
951     mEventLogger.logNanoappUnload(*nanoappId, response.success);
952     if (auto callback = mHalClientManager->getCallback(clientId);
953         callback != nullptr) {
954       LOGD("Unload transaction %" PRIu32 " for nanoapp 0x%" PRIx64
955            " client id %" PRIu16 " is finished: %s",
956            response.transaction_id, *nanoappId, clientId,
957            response.success ? "success" : "failure");
958       callback->handleTransactionResult(response.transaction_id,
959                                         /* in_success= */ response.success);
960     }
961   }
962   // TODO(b/242760291): Remove the nanoapp log detokenizer associated with this
963   // nanoapp.
964 }
965 
onNanoappMessage(const::chre::fbs::NanoappMessageT & message)966 void MultiClientContextHubBase::onNanoappMessage(
967     const ::chre::fbs::NanoappMessageT &message) {
968   mEventLogger.logMessageFromNanoapp(message);
969   ContextHubMessage outMessage;
970   outMessage.nanoappId = message.app_id;
971   outMessage.hostEndPoint = message.host_endpoint;
972   outMessage.messageType = message.message_type;
973   outMessage.messageBody = message.message;
974   outMessage.permissions = chreToAndroidPermissions(message.permissions);
975   outMessage.isReliable = message.is_reliable;
976   outMessage.messageSequenceNumber = message.message_sequence_number;
977 
978   std::string messageSeq = "reliable message seq=" +
979                            std::to_string(outMessage.messageSequenceNumber);
980   LOGD("Received a nanoapp message from 0x%" PRIx64 " endpoint 0x%" PRIx16
981        ": Type 0x%" PRIx32 " size %zu %s",
982        outMessage.nanoappId, outMessage.hostEndPoint, outMessage.messageType,
983        outMessage.messageBody.size(),
984        outMessage.isReliable ? messageSeq.c_str() : "");
985 
986   std::vector<std::string> messageContentPerms =
987       chreToAndroidPermissions(message.message_permissions);
988   // broadcast message is sent to every connected endpoint
989   if (message.host_endpoint == CHRE_HOST_ENDPOINT_BROADCAST) {
990     mHalClientManager->sendMessageForAllCallbacks(outMessage,
991                                                   messageContentPerms);
992   } else if (auto callback = mHalClientManager->getCallbackForEndpoint(
993                  message.host_endpoint);
994              callback != nullptr) {
995     outMessage.hostEndPoint =
996         HalClientManager::convertToOriginalEndpointId(message.host_endpoint);
997     callback->handleContextHubMessage(outMessage, messageContentPerms);
998   }
999 
1000   if (mMetricsReporter != nullptr && message.woke_host) {
1001     mMetricsReporter->logApWakeupOccurred(message.app_id);
1002   }
1003 }
1004 
onMessageDeliveryStatus(const::chre::fbs::MessageDeliveryStatusT & status)1005 void MultiClientContextHubBase::onMessageDeliveryStatus(
1006     const ::chre::fbs::MessageDeliveryStatusT &status) {
1007   HostEndpointId hostEndpointId;
1008   if (bug_fix_hal_reliable_message_record()) {
1009     {
1010       std::lock_guard<std::mutex> lock(mReliableMessageMutex);
1011       auto iter = std::find_if(
1012           mReliableMessageQueue.begin(), mReliableMessageQueue.end(),
1013           [&status](const ReliableMessageRecord &record) {
1014             return record.messageSequenceNumber == status.message_sequence_number;
1015           });
1016       if (iter == mReliableMessageQueue.end()) {
1017         LOGE(
1018             "Unable to get the host endpoint ID for message "
1019             "sequence number: %" PRIu32,
1020             status.message_sequence_number);
1021         return;
1022       }
1023 
1024       hostEndpointId = iter->hostEndpointId;
1025       cleanupReliableMessageQueueLocked();
1026     }
1027   } else {
1028     auto hostEndpointIdIter =
1029         mReliableMessageMap.find(status.message_sequence_number);
1030     if (hostEndpointIdIter == mReliableMessageMap.end()) {
1031       LOGE(
1032           "Unable to get the host endpoint ID for message sequence "
1033           "number: %" PRIu32,
1034           status.message_sequence_number);
1035       return;
1036     }
1037 
1038     hostEndpointId = hostEndpointIdIter->second;
1039     mReliableMessageMap.erase(hostEndpointIdIter);
1040   }
1041 
1042   std::shared_ptr<IContextHubCallback> callback =
1043       mHalClientManager->getCallbackForEndpoint(hostEndpointId);
1044   if (callback == nullptr) {
1045     LOGE("Could not get callback for host endpoint: %" PRIu16, hostEndpointId);
1046     return;
1047   }
1048   hostEndpointId =
1049       HalClientManager::convertToOriginalEndpointId(hostEndpointId);
1050 
1051   MessageDeliveryStatus outStatus;
1052   outStatus.messageSequenceNumber = status.message_sequence_number;
1053   outStatus.errorCode = toErrorCode(status.error_code);
1054   callback->handleMessageDeliveryStatus(hostEndpointId, outStatus);
1055 }
1056 
onClientDied(void * cookie)1057 void MultiClientContextHubBase::onClientDied(void *cookie) {
1058   auto *info = static_cast<HalDeathRecipientCookie *>(cookie);
1059   info->hal->handleClientDeath(info->clientPid);
1060 }
1061 
handleClientDeath(pid_t clientPid)1062 void MultiClientContextHubBase::handleClientDeath(pid_t clientPid) {
1063   LOGI("Process %d is dead. Cleaning up.", clientPid);
1064   if (auto endpoints = mHalClientManager->getAllConnectedEndpoints(clientPid)) {
1065     for (auto endpointId : *endpoints) {
1066       LOGD("Sending message to remove endpoint 0x%" PRIx16, endpointId);
1067       if (!mHalClientManager->mutateEndpointIdFromHostIfNeeded(clientPid,
1068                                                                endpointId)) {
1069         continue;
1070       }
1071       flatbuffers::FlatBufferBuilder builder(64);
1072       HostProtocolHost::encodeHostEndpointDisconnected(builder, endpointId);
1073       mConnection->sendMessage(builder);
1074     }
1075   }
1076   mHalClientManager->handleClientDeath(clientPid);
1077 }
1078 
onChreDisconnected()1079 void MultiClientContextHubBase::onChreDisconnected() {
1080   mIsChreReady = false;
1081   LOGW("HAL APIs will be failed because CHRE is disconnected");
1082   if (mV4Impl) mV4Impl->onChreDisconnected();
1083 }
1084 
onChreRestarted()1085 void MultiClientContextHubBase::onChreRestarted() {
1086   mIsWifiAvailable.reset();
1087   mEventLogger.logContextHubRestart();
1088   mHalClientManager->handleChreRestart();
1089   if (mV4Impl) mV4Impl->onChreRestarted();
1090 
1091   // Unblock APIs BEFORE informing the clients that CHRE has restarted so that
1092   // any API call triggered by handleContextHubAsyncEvent() can come through.
1093   mIsChreReady = true;
1094   LOGI("HAL APIs are re-enabled");
1095   std::vector<std::shared_ptr<IContextHubCallback>> callbacks =
1096       mHalClientManager->getCallbacks();
1097   for (auto callback : callbacks) {
1098     callback->handleContextHubAsyncEvent(AsyncEventType::RESTARTED);
1099   }
1100 }
1101 
dump(int fd,const char **,uint32_t)1102 binder_status_t MultiClientContextHubBase::dump(int fd,
1103                                                 const char ** /* args */,
1104                                                 uint32_t /* numArgs */) {
1105   // Dump of CHRE debug data. It waits for the dump to finish before returning.
1106   debugDumpStart(fd);
1107 
1108   if (!WriteStringToFd("\n-- Context Hub HAL dump --\n", fd)) {
1109     LOGW("Failed to write the Context Hub HAL dump banner");
1110   }
1111 
1112   // Dump debug info of HalClientManager.
1113   std::string dumpOfHalClientManager = mHalClientManager->debugDump();
1114   if (!WriteStringToFd(dumpOfHalClientManager, fd)) {
1115     LOGW("Failed to write debug dump of HalClientManager. Size: %zu",
1116          dumpOfHalClientManager.size());
1117   }
1118 
1119   // Dump the status of test mode
1120   std::ostringstream testModeDump;
1121   {
1122     std::lock_guard<std::mutex> lockGuard(mTestModeMutex);
1123     testModeDump << "\nTest mode: "
1124                  << (mIsTestModeEnabled ? "Enabled" : "Disabled") << "\n";
1125     if (!mTestModeNanoapps.has_value()) {
1126       testModeDump << "\nError: Nanoapp list is left unset\n";
1127     }
1128   }
1129   if (!WriteStringToFd(testModeDump.str(), fd)) {
1130     LOGW("Failed to write test mode dump");
1131   }
1132 
1133   // Dump the status of ChreConnection
1134   std::string chreConnectionDump = mConnection->dump();
1135   if (!WriteStringToFd(chreConnectionDump, fd)) {
1136     LOGW("Failed to write ChreConnection dump. Size: %zu",
1137          chreConnectionDump.size());
1138   }
1139 
1140   if (!WriteStringToFd("\n-- End of Context Hub HAL dump --\n\n", fd)) {
1141     LOGW("Failed to write the end dump banner");
1142   }
1143 
1144   return STATUS_OK;
1145 }
1146 
requestDebugDump()1147 bool MultiClientContextHubBase::requestDebugDump() {
1148   flatbuffers::FlatBufferBuilder builder;
1149   HostProtocolHost::encodeDebugDumpRequest(builder);
1150   return mConnection->sendMessage(builder);
1151 }
1152 
writeToDebugFile(const char * str)1153 void MultiClientContextHubBase::writeToDebugFile(const char *str) {
1154   if (!WriteStringToFd(std::string(str), getDebugFd())) {
1155     LOGW("Failed to write %zu bytes to debug dump fd", strlen(str));
1156   }
1157 }
1158 
handleLogMessageV2(const::chre::fbs::LogMessageV2T & logMessage)1159 void MultiClientContextHubBase::handleLogMessageV2(
1160     const ::chre::fbs::LogMessageV2T &logMessage) {
1161   const std::vector<int8_t> &logBuffer = logMessage.buffer;
1162   auto logData = reinterpret_cast<const uint8_t *>(logBuffer.data());
1163   uint32_t numLogsDropped = logMessage.num_logs_dropped;
1164   mLogger.logV2(logData, logBuffer.size(), numLogsDropped);
1165 }
1166 
onMetricLog(const::chre::fbs::MetricLogT & metricMessage)1167 void MultiClientContextHubBase::onMetricLog(
1168     const ::chre::fbs::MetricLogT &metricMessage) {
1169   if (mMetricsReporter == nullptr) {
1170     return;
1171   }
1172 
1173   using ::android::chre::Atoms::ChrePalOpenFailed;
1174 
1175   const std::vector<int8_t> &encodedMetric = metricMessage.encoded_metric;
1176   auto metricSize = static_cast<int>(encodedMetric.size());
1177 
1178   switch (metricMessage.id) {
1179     case Atoms::CHRE_PAL_OPEN_FAILED: {
1180       metrics::ChrePalOpenFailed metric;
1181       if (!metric.ParseFromArray(encodedMetric.data(), metricSize)) {
1182         break;
1183       }
1184       auto pal = static_cast<ChrePalOpenFailed::ChrePalType>(metric.pal());
1185       auto type = static_cast<ChrePalOpenFailed::Type>(metric.type());
1186       if (!mMetricsReporter->logPalOpenFailed(pal, type)) {
1187         LOGE("Could not log the PAL open failed metric");
1188       }
1189       return;
1190     }
1191     case Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED: {
1192       metrics::ChreEventQueueSnapshotReported metric;
1193       if (!metric.ParseFromArray(encodedMetric.data(), metricSize)) {
1194         break;
1195       }
1196       if (!mMetricsReporter->logEventQueueSnapshotReported(
1197               metric.snapshot_chre_get_time_ms(), metric.max_event_queue_size(),
1198               metric.mean_event_queue_size(), metric.num_dropped_events())) {
1199         LOGE("Could not log the event queue snapshot metric");
1200       }
1201       return;
1202     }
1203     default: {
1204       LOGW("Unknown metric ID %" PRIu32, metricMessage.id);
1205       return;
1206     }
1207   }
1208   // Reached here only if an error has occurred for a known metric id.
1209   LOGE("Failed to parse metric data with id %" PRIu32, metricMessage.id);
1210 }
1211 
cleanupReliableMessageQueueLocked()1212 void MultiClientContextHubBase::cleanupReliableMessageQueueLocked() {
1213   while (!mReliableMessageQueue.empty() &&
1214          mReliableMessageQueue.front().isExpired()) {
1215     std::pop_heap(mReliableMessageQueue.begin(), mReliableMessageQueue.end(),
1216                   std::greater<ReliableMessageRecord>());
1217     mReliableMessageQueue.pop_back();
1218   }
1219 }
1220 
1221 }  // namespace android::hardware::contexthub::common::implementation
1222