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