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