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