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 #include <chre/platform/shared/host_protocol_common.h>
19 #include <chre_host/generated/host_messages_generated.h>
20 #include <chre_host/log.h>
21 #include "chre/event.h"
22 #include "chre_host/config_util.h"
23 #include "chre_host/file_stream.h"
24 #include "chre_host/fragmented_load_transaction.h"
25 #include "chre_host/host_protocol_host.h"
26 #include "permissions_util.h"
27
28 namespace android::hardware::contexthub::common::implementation {
29
30 using ::android::chre::FragmentedLoadTransaction;
31 using ::android::chre::getStringFromByteVector;
32 using ::ndk::ScopedAStatus;
33 namespace fbs = ::chre::fbs;
34
35 namespace {
36 constexpr uint32_t kDefaultHubId = 0;
37
38 // timeout for calling getContextHubs(), which is synchronous
39 constexpr auto kHubInfoQueryTimeout = std::chrono::seconds(5);
40
41 enum class HalErrorCode : int32_t {
42 OPERATION_FAILED = -1,
43 INVALID_RESULT = -2,
44 INVALID_ARGUMENT = -3,
45 };
46
isValidContextHubId(uint32_t hubId)47 bool isValidContextHubId(uint32_t hubId) {
48 if (hubId != kDefaultHubId) {
49 LOGE("Invalid context hub ID %" PRId32, hubId);
50 return false;
51 }
52 return true;
53 }
54
getFbsSetting(const Setting & setting,fbs::Setting * fbsSetting)55 bool getFbsSetting(const Setting &setting, fbs::Setting *fbsSetting) {
56 bool foundSetting = true;
57 switch (setting) {
58 case Setting::LOCATION:
59 *fbsSetting = fbs::Setting::LOCATION;
60 break;
61 case Setting::AIRPLANE_MODE:
62 *fbsSetting = fbs::Setting::AIRPLANE_MODE;
63 break;
64 case Setting::MICROPHONE:
65 *fbsSetting = fbs::Setting::MICROPHONE;
66 break;
67 default:
68 foundSetting = false;
69 LOGE("Setting update with invalid enum value %hhu", setting);
70 break;
71 }
72 return foundSetting;
73 }
74
toFbsSettingState(bool enabled)75 chre::fbs::SettingState toFbsSettingState(bool enabled) {
76 return enabled ? chre::fbs::SettingState::ENABLED
77 : chre::fbs::SettingState::DISABLED;
78 }
79
80 // functions that extract different version numbers
extractChreApiMajorVersion(uint32_t chreVersion)81 inline constexpr int8_t extractChreApiMajorVersion(uint32_t chreVersion) {
82 return static_cast<int8_t>(chreVersion >> 24);
83 }
extractChreApiMinorVersion(uint32_t chreVersion)84 inline constexpr int8_t extractChreApiMinorVersion(uint32_t chreVersion) {
85 return static_cast<int8_t>(chreVersion >> 16);
86 }
extractChrePatchVersion(uint32_t chreVersion)87 inline constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
88 return static_cast<uint16_t>(chreVersion);
89 }
90
91 // functions that help to generate ScopedAStatus from different values.
fromServiceError(HalErrorCode errorCode)92 inline ScopedAStatus fromServiceError(HalErrorCode errorCode) {
93 return ScopedAStatus::fromServiceSpecificError(
94 static_cast<int32_t>(errorCode));
95 }
fromResult(bool result)96 inline ScopedAStatus fromResult(bool result) {
97 return result ? ScopedAStatus::ok()
98 : fromServiceError(HalErrorCode::OPERATION_FAILED);
99 }
100 } // anonymous namespace
101
getContextHubs(std::vector<ContextHubInfo> * contextHubInfos)102 ScopedAStatus MultiClientContextHubBase::getContextHubs(
103 std::vector<ContextHubInfo> *contextHubInfos) {
104 std::unique_lock<std::mutex> lock(mHubInfoMutex);
105 if (mContextHubInfo == nullptr) {
106 fbs::HubInfoResponseT response;
107 flatbuffers::FlatBufferBuilder builder;
108 HostProtocolHost::encodeHubInfoRequest(builder);
109 if (!mConnection->sendMessage(builder)) {
110 LOGE("Failed to send a message to CHRE to get context hub info.");
111 return fromServiceError(HalErrorCode::OPERATION_FAILED);
112 }
113 mHubInfoCondition.wait_for(lock, kHubInfoQueryTimeout,
114 [this]() { return mContextHubInfo != nullptr; });
115 }
116 if (mContextHubInfo != nullptr) {
117 contextHubInfos->push_back(*mContextHubInfo);
118 return ScopedAStatus::ok();
119 }
120 LOGE("Unable to get a valid context hub info for PID %d",
121 AIBinder_getCallingPid());
122 return fromServiceError(HalErrorCode::INVALID_RESULT);
123 }
124
loadNanoapp(int32_t contextHubId,const NanoappBinary & appBinary,int32_t transactionId)125 ScopedAStatus MultiClientContextHubBase::loadNanoapp(
126 int32_t contextHubId, const NanoappBinary &appBinary,
127 int32_t transactionId) {
128 if (!isValidContextHubId(contextHubId)) {
129 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
130 }
131 LOGI("Loading nanoapp 0x%" PRIx64, appBinary.nanoappId);
132 uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
133 (appBinary.targetChreApiMinorVersion << 16);
134 auto transaction = std::make_unique<FragmentedLoadTransaction>(
135 transactionId, appBinary.nanoappId, appBinary.nanoappVersion,
136 appBinary.flags, targetApiVersion, appBinary.customBinary,
137 mConnection->getLoadFragmentSizeBytes());
138 if (!mHalClientManager->registerPendingLoadTransaction(
139 std::move(transaction))) {
140 return fromResult(false);
141 }
142 auto clientId = mHalClientManager->getClientId();
143 auto request = mHalClientManager->getNextFragmentedLoadRequest();
144
145 if (request.has_value() &&
146 sendFragmentedLoadRequest(clientId, request.value())) {
147 return ScopedAStatus::ok();
148 }
149 LOGE("Failed to send the first load request for nanoapp 0x%" PRIx64,
150 appBinary.nanoappId);
151 mHalClientManager->resetPendingLoadTransaction();
152 return fromResult(false);
153 }
154
sendFragmentedLoadRequest(HalClientId clientId,FragmentedLoadRequest & request)155 bool MultiClientContextHubBase::sendFragmentedLoadRequest(
156 HalClientId clientId, FragmentedLoadRequest &request) {
157 flatbuffers::FlatBufferBuilder builder(128 + request.binary.size());
158 HostProtocolHost::encodeFragmentedLoadNanoappRequest(
159 builder, request, /* respondBeforeStart= */ false);
160 HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
161 builder.GetSize(), clientId);
162 return mConnection->sendMessage(builder);
163 }
164
unloadNanoapp(int32_t contextHubId,int64_t appId,int32_t transactionId)165 ScopedAStatus MultiClientContextHubBase::unloadNanoapp(int32_t contextHubId,
166 int64_t appId,
167 int32_t transactionId) {
168 if (!isValidContextHubId(contextHubId)) {
169 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
170 }
171 if (!mHalClientManager->registerPendingUnloadTransaction(transactionId)) {
172 return fromResult(false);
173 }
174 HalClientId clientId = mHalClientManager->getClientId();
175 flatbuffers::FlatBufferBuilder builder(64);
176 HostProtocolHost::encodeUnloadNanoappRequest(
177 builder, transactionId, appId, /* allowSystemNanoappUnload= */ false);
178 HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
179 builder.GetSize(), clientId);
180
181 bool result = mConnection->sendMessage(builder);
182 if (!result) {
183 mHalClientManager->resetPendingUnloadTransaction(clientId, transactionId);
184 }
185 return fromResult(result);
186 }
187
disableNanoapp(int32_t,int64_t appId,int32_t)188 ScopedAStatus MultiClientContextHubBase::disableNanoapp(
189 int32_t /* contextHubId */, int64_t appId, int32_t /* transactionId */) {
190 LOGW("Attempted to disable app ID 0x%016" PRIx64 ", but not supported",
191 appId);
192 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
193 }
194
enableNanoapp(int32_t,int64_t appId,int32_t)195 ScopedAStatus MultiClientContextHubBase::enableNanoapp(
196 int32_t /* contextHubId */, int64_t appId, int32_t /* transactionId */) {
197 LOGW("Attempted to enable app ID 0x%016" PRIx64 ", but not supported", appId);
198 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
199 }
200
onSettingChanged(Setting setting,bool enabled)201 ScopedAStatus MultiClientContextHubBase::onSettingChanged(Setting setting,
202 bool enabled) {
203 mSettingEnabled[setting] = enabled;
204 fbs::Setting fbsSetting;
205 bool isWifiOrBtSetting =
206 (setting == Setting::WIFI_MAIN || setting == Setting::WIFI_SCANNING ||
207 setting == Setting::BT_MAIN || setting == Setting::BT_SCANNING);
208 if (!isWifiOrBtSetting && getFbsSetting(setting, &fbsSetting)) {
209 flatbuffers::FlatBufferBuilder builder(64);
210 HostProtocolHost::encodeSettingChangeNotification(
211 builder, fbsSetting, toFbsSettingState(enabled));
212 mConnection->sendMessage(builder);
213 }
214
215 bool isWifiMainEnabled = isSettingEnabled(Setting::WIFI_MAIN);
216 bool isWifiScanEnabled = isSettingEnabled(Setting::WIFI_SCANNING);
217 bool isAirplaneModeEnabled = isSettingEnabled(Setting::AIRPLANE_MODE);
218
219 // Because the airplane mode impact on WiFi is not standardized in Android,
220 // we write a specific handling in the Context Hub HAL to inform CHRE.
221 // The following definition is a default one, and can be adjusted
222 // appropriately if necessary.
223 bool isWifiAvailable = isAirplaneModeEnabled
224 ? (isWifiMainEnabled)
225 : (isWifiMainEnabled || isWifiScanEnabled);
226 if (!mIsWifiAvailable.has_value() || (isWifiAvailable != mIsWifiAvailable)) {
227 flatbuffers::FlatBufferBuilder builder(64);
228 HostProtocolHost::encodeSettingChangeNotification(
229 builder, fbs::Setting::WIFI_AVAILABLE,
230 toFbsSettingState(isWifiAvailable));
231 mConnection->sendMessage(builder);
232 mIsWifiAvailable = isWifiAvailable;
233 }
234
235 // The BT switches determine whether we can BLE scan which is why things are
236 // mapped like this into CHRE.
237 bool isBtMainEnabled = isSettingEnabled(Setting::BT_MAIN);
238 bool isBtScanEnabled = isSettingEnabled(Setting::BT_SCANNING);
239 bool isBleAvailable = isBtMainEnabled || isBtScanEnabled;
240 if (!mIsBleAvailable.has_value() || (isBleAvailable != mIsBleAvailable)) {
241 flatbuffers::FlatBufferBuilder builder(64);
242 HostProtocolHost::encodeSettingChangeNotification(
243 builder, fbs::Setting::BLE_AVAILABLE,
244 toFbsSettingState(isBleAvailable));
245 mConnection->sendMessage(builder);
246 mIsBleAvailable = isBleAvailable;
247 }
248
249 return ScopedAStatus::ok();
250 }
251
queryNanoapps(int32_t contextHubId)252 ScopedAStatus MultiClientContextHubBase::queryNanoapps(int32_t contextHubId) {
253 if (!isValidContextHubId(contextHubId)) {
254 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
255 }
256 flatbuffers::FlatBufferBuilder builder(64);
257 HostProtocolHost::encodeNanoappListRequest(builder);
258 HostProtocolHost::mutateHostClientId(builder.GetBufferPointer(),
259 builder.GetSize(),
260 mHalClientManager->getClientId());
261 return fromResult(mConnection->sendMessage(builder));
262 }
263
getPreloadedNanoappIds(int32_t contextHubId,std::vector<int64_t> * out_preloadedNanoappIds)264 ScopedAStatus MultiClientContextHubBase::getPreloadedNanoappIds(
265 int32_t contextHubId, std::vector<int64_t> *out_preloadedNanoappIds) {
266 if (contextHubId != kDefaultHubId) {
267 LOGE("Invalid ID %" PRId32, contextHubId);
268 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
269 }
270 if (out_preloadedNanoappIds == nullptr) {
271 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
272 }
273 std::unique_lock<std::mutex> lock(mPreloadedNanoappIdsMutex);
274 if (!mPreloadedNanoappIds.has_value()) {
275 mPreloadedNanoappIds = std::vector<uint64_t>{};
276 mPreloadedNanoappLoader->getPreloadedNanoappIds(*mPreloadedNanoappIds);
277 }
278 for (const auto &nanoappId : mPreloadedNanoappIds.value()) {
279 out_preloadedNanoappIds->emplace_back(static_cast<uint64_t>(nanoappId));
280 }
281 return ScopedAStatus::ok();
282 }
283
registerCallback(int32_t contextHubId,const std::shared_ptr<IContextHubCallback> & callback)284 ScopedAStatus MultiClientContextHubBase::registerCallback(
285 int32_t contextHubId,
286 const std::shared_ptr<IContextHubCallback> &callback) {
287 if (!isValidContextHubId(contextHubId)) {
288 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
289 }
290 if (callback == nullptr) {
291 LOGE("Callback of context hub HAL must not be null");
292 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
293 }
294 // If everything is successful cookie will be released by the callback of
295 // binder unlinking (callback overridden).
296 auto *cookie = new HalDeathRecipientCookie(this, AIBinder_getCallingPid());
297 if (!mHalClientManager->registerCallback(callback, mDeathRecipient, cookie)) {
298 LOGE("Unable to register the callback");
299 delete cookie;
300 return fromResult(false);
301 }
302 return ScopedAStatus::ok();
303 }
304
sendMessageToHub(int32_t contextHubId,const ContextHubMessage & message)305 ScopedAStatus MultiClientContextHubBase::sendMessageToHub(
306 int32_t contextHubId, const ContextHubMessage &message) {
307 if (!isValidContextHubId(contextHubId)) {
308 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
309 }
310 HostEndpointId hostEndpointId = message.hostEndPoint;
311 if (!mHalClientManager->mutateEndpointIdFromHostIfNeeded(
312 AIBinder_getCallingPid(), hostEndpointId)) {
313 return fromResult(false);
314 }
315 flatbuffers::FlatBufferBuilder builder(1024);
316 HostProtocolHost::encodeNanoappMessage(
317 builder, message.nanoappId, message.messageType, hostEndpointId,
318 message.messageBody.data(), message.messageBody.size());
319 return fromResult(mConnection->sendMessage(builder));
320 }
321
onHostEndpointConnected(const HostEndpointInfo & info)322 ScopedAStatus MultiClientContextHubBase::onHostEndpointConnected(
323 const HostEndpointInfo &info) {
324 uint8_t type;
325 switch (info.type) {
326 case HostEndpointInfo::Type::APP:
327 type = CHRE_HOST_ENDPOINT_TYPE_APP;
328 break;
329 case HostEndpointInfo::Type::NATIVE:
330 type = CHRE_HOST_ENDPOINT_TYPE_NATIVE;
331 break;
332 case HostEndpointInfo::Type::FRAMEWORK:
333 type = CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK;
334 break;
335 default:
336 LOGE("Unsupported host endpoint type %" PRIu32, info.type);
337 return fromServiceError(HalErrorCode::INVALID_ARGUMENT);
338 }
339
340 uint16_t endpointId = info.hostEndpointId;
341 if (!mHalClientManager->registerEndpointId(info.hostEndpointId) ||
342 !mHalClientManager->mutateEndpointIdFromHostIfNeeded(
343 AIBinder_getCallingPid(), endpointId)) {
344 return fromServiceError(HalErrorCode::INVALID_ARGUMENT);
345 }
346 flatbuffers::FlatBufferBuilder builder(64);
347 HostProtocolHost::encodeHostEndpointConnected(
348 builder, endpointId, type, info.packageName.value_or(std::string()),
349 info.attributionTag.value_or(std::string()));
350 return fromResult(mConnection->sendMessage(builder));
351 }
352
onHostEndpointDisconnected(char16_t in_hostEndpointId)353 ScopedAStatus MultiClientContextHubBase::onHostEndpointDisconnected(
354 char16_t in_hostEndpointId) {
355 HostEndpointId hostEndpointId = in_hostEndpointId;
356 bool isSuccessful = false;
357 if (mHalClientManager->removeEndpointId(hostEndpointId) &&
358 mHalClientManager->mutateEndpointIdFromHostIfNeeded(
359 AIBinder_getCallingPid(), hostEndpointId)) {
360 flatbuffers::FlatBufferBuilder builder(64);
361 HostProtocolHost::encodeHostEndpointDisconnected(builder, hostEndpointId);
362 isSuccessful = mConnection->sendMessage(builder);
363 }
364 if (!isSuccessful) {
365 LOGW("Unable to remove host endpoint id %" PRIu16, in_hostEndpointId);
366 }
367 return ScopedAStatus::ok();
368 }
369
onNanSessionStateChanged(const NanSessionStateUpdate &)370 ScopedAStatus MultiClientContextHubBase::onNanSessionStateChanged(
371 const NanSessionStateUpdate & /*in_update*/) {
372 // TODO(271471342): Add support for NAN session management.
373 return ndk::ScopedAStatus::ok();
374 }
375
setTestMode(bool)376 ScopedAStatus MultiClientContextHubBase::setTestMode(bool /*enable*/) {
377 // To be implemented.
378 return ScopedAStatus::ok();
379 }
380
handleMessageFromChre(const unsigned char * messageBuffer,size_t messageLen)381 void MultiClientContextHubBase::handleMessageFromChre(
382 const unsigned char *messageBuffer, size_t messageLen) {
383 if (!::chre::HostProtocolCommon::verifyMessage(messageBuffer, messageLen)) {
384 LOGE("Invalid message received from CHRE.");
385 return;
386 }
387 std::unique_ptr<fbs::MessageContainerT> container =
388 fbs::UnPackMessageContainer(messageBuffer);
389 fbs::ChreMessageUnion &message = container->message;
390 HalClientId clientId = container->host_addr->client_id();
391
392 switch (container->message.type) {
393 case fbs::ChreMessage::HubInfoResponse: {
394 handleHubInfoResponse(*message.AsHubInfoResponse());
395 break;
396 }
397 case fbs::ChreMessage::NanoappListResponse: {
398 onNanoappListResponse(*message.AsNanoappListResponse(), clientId);
399 break;
400 }
401 case fbs::ChreMessage::LoadNanoappResponse: {
402 onNanoappLoadResponse(*message.AsLoadNanoappResponse(), clientId);
403 break;
404 }
405 case fbs::ChreMessage::UnloadNanoappResponse: {
406 onNanoappUnloadResponse(*message.AsUnloadNanoappResponse(), clientId);
407 break;
408 }
409 case fbs::ChreMessage::NanoappMessage: {
410 onNanoappMessage(*message.AsNanoappMessage());
411 break;
412 }
413 default:
414 LOGW("Got unexpected message type %" PRIu8,
415 static_cast<uint8_t>(message.type));
416 }
417 }
418
handleHubInfoResponse(const fbs::HubInfoResponseT & response)419 void MultiClientContextHubBase::handleHubInfoResponse(
420 const fbs::HubInfoResponseT &response) {
421 std::unique_lock<std::mutex> lock(mHubInfoMutex);
422 mContextHubInfo = std::make_unique<ContextHubInfo>();
423 mContextHubInfo->name = getStringFromByteVector(response.name);
424 mContextHubInfo->vendor = getStringFromByteVector(response.vendor);
425 mContextHubInfo->toolchain = getStringFromByteVector(response.toolchain);
426 mContextHubInfo->id = kDefaultHubId;
427 mContextHubInfo->peakMips = response.peak_mips;
428 mContextHubInfo->maxSupportedMessageLengthBytes = response.max_msg_len;
429 mContextHubInfo->chrePlatformId = response.platform_id;
430 uint32_t version = response.chre_platform_version;
431 mContextHubInfo->chreApiMajorVersion = extractChreApiMajorVersion(version);
432 mContextHubInfo->chreApiMinorVersion = extractChreApiMinorVersion(version);
433 mContextHubInfo->chrePatchVersion = extractChrePatchVersion(version);
434 mContextHubInfo->supportedPermissions = kSupportedPermissions;
435 mHubInfoCondition.notify_all();
436 }
437
onNanoappListResponse(const fbs::NanoappListResponseT & response,HalClientId clientId)438 void MultiClientContextHubBase::onNanoappListResponse(
439 const fbs::NanoappListResponseT &response, HalClientId clientId) {
440 std::shared_ptr<IContextHubCallback> callback =
441 mHalClientManager->getCallback(clientId);
442 if (callback == nullptr) {
443 return;
444 }
445 std::vector<NanoappInfo> appInfoList;
446 for (const auto &nanoapp : response.nanoapps) {
447 if (nanoapp == nullptr || nanoapp->is_system) {
448 continue;
449 }
450 NanoappInfo appInfo;
451 appInfo.nanoappId = nanoapp->app_id;
452 appInfo.nanoappVersion = nanoapp->version;
453 appInfo.enabled = nanoapp->enabled;
454 appInfo.permissions = chreToAndroidPermissions(nanoapp->permissions);
455
456 std::vector<NanoappRpcService> rpcServices;
457 for (const auto &service : nanoapp->rpc_services) {
458 NanoappRpcService aidlService;
459 aidlService.id = service->id;
460 aidlService.version = service->version;
461 rpcServices.emplace_back(aidlService);
462 }
463 appInfo.rpcServices = rpcServices;
464 appInfoList.push_back(appInfo);
465 }
466 callback->handleNanoappInfo(appInfoList);
467 }
468
onNanoappLoadResponse(const fbs::LoadNanoappResponseT & response,HalClientId clientId)469 void MultiClientContextHubBase::onNanoappLoadResponse(
470 const fbs::LoadNanoappResponseT &response, HalClientId clientId) {
471 LOGD("Received nanoapp load response for client %" PRIu16
472 " transaction %" PRIu32 " fragment %" PRIu32,
473 clientId, response.transaction_id, response.fragment_id);
474 if (mPreloadedNanoappLoader->isPreloadOngoing()) {
475 mPreloadedNanoappLoader->onLoadNanoappResponse(response, clientId);
476 return;
477 }
478 if (!mHalClientManager->isPendingLoadTransactionExpected(
479 clientId, response.transaction_id, response.fragment_id)) {
480 LOGW("Received a response for client %" PRIu16 " transaction %" PRIu32
481 " fragment %" PRIu32
482 " that doesn't match the existing transaction. Skipped.",
483 clientId, response.transaction_id, response.fragment_id);
484 return;
485 }
486 if (response.success) {
487 auto nextFragmentedRequest =
488 mHalClientManager->getNextFragmentedLoadRequest();
489 if (nextFragmentedRequest.has_value()) {
490 // nextFragmentedRequest will only have a value if the pending transaction
491 // matches the response and there are more fragments to send. Hold off on
492 // calling the callback in this case.
493 LOGD("Sending next FragmentedLoadRequest for client %" PRIu16
494 ": (transaction: %" PRIu32 ", fragment %zu)",
495 clientId, nextFragmentedRequest->transactionId,
496 nextFragmentedRequest->fragmentId);
497 sendFragmentedLoadRequest(clientId, nextFragmentedRequest.value());
498 return;
499 }
500 } else {
501 LOGE("Loading nanoapp fragment for client %" PRIu16 " transaction %" PRIu32
502 " fragment %" PRIu32 " failed",
503 clientId, response.transaction_id, response.fragment_id);
504 mHalClientManager->resetPendingLoadTransaction();
505 }
506 // At this moment the current pending transaction should either have no more
507 // fragment to send or the response indicates its last nanoapp fragment fails
508 // to get loaded.
509 if (auto callback = mHalClientManager->getCallback(clientId);
510 callback != nullptr) {
511 callback->handleTransactionResult(response.transaction_id,
512 /* in_success= */ response.success);
513 }
514 }
515
onNanoappUnloadResponse(const fbs::UnloadNanoappResponseT & response,HalClientId clientId)516 void MultiClientContextHubBase::onNanoappUnloadResponse(
517 const fbs::UnloadNanoappResponseT &response, HalClientId clientId) {
518 if (mHalClientManager->resetPendingUnloadTransaction(
519 clientId, response.transaction_id)) {
520 if (auto callback = mHalClientManager->getCallback(clientId);
521 callback != nullptr) {
522 callback->handleTransactionResult(response.transaction_id,
523 /* in_success= */ response.success);
524 }
525 }
526 }
527
onNanoappMessage(const::chre::fbs::NanoappMessageT & message)528 void MultiClientContextHubBase::onNanoappMessage(
529 const ::chre::fbs::NanoappMessageT &message) {
530 ContextHubMessage outMessage;
531 outMessage.nanoappId = message.app_id;
532 outMessage.hostEndPoint = message.host_endpoint;
533 outMessage.messageType = message.message_type;
534 outMessage.messageBody = message.message;
535 outMessage.permissions = chreToAndroidPermissions(message.permissions);
536 auto messageContentPerms =
537 chreToAndroidPermissions(message.message_permissions);
538 // broadcast message is sent to every connected endpoint
539 if (message.host_endpoint == CHRE_HOST_ENDPOINT_BROADCAST) {
540 mHalClientManager->sendMessageForAllCallbacks(outMessage,
541 messageContentPerms);
542 } else if (auto callback = mHalClientManager->getCallbackForEndpoint(
543 message.host_endpoint);
544 callback != nullptr) {
545 outMessage.hostEndPoint =
546 HalClientManager::convertToOriginalEndpointId(message.host_endpoint);
547 callback->handleContextHubMessage(outMessage, messageContentPerms);
548 }
549 }
550
onClientDied(void * cookie)551 void MultiClientContextHubBase::onClientDied(void *cookie) {
552 auto *info = static_cast<HalDeathRecipientCookie *>(cookie);
553 info->hal->handleClientDeath(info->clientPid);
554 }
555
handleClientDeath(pid_t clientPid)556 void MultiClientContextHubBase::handleClientDeath(pid_t clientPid) {
557 LOGI("Process %d is dead. Cleaning up.", clientPid);
558 if (auto endpoints = mHalClientManager->getAllConnectedEndpoints(clientPid)) {
559 for (auto endpointId : *endpoints) {
560 LOGI("Sending message to remove endpoint 0x%" PRIx16, endpointId);
561 if (!mHalClientManager->mutateEndpointIdFromHostIfNeeded(clientPid,
562 endpointId)) {
563 continue;
564 }
565 flatbuffers::FlatBufferBuilder builder(64);
566 HostProtocolHost::encodeHostEndpointDisconnected(builder, endpointId);
567 mConnection->sendMessage(builder);
568 }
569 }
570 mHalClientManager->handleClientDeath(clientPid, mDeathRecipient);
571 }
572
onChreRestarted()573 void MultiClientContextHubBase::onChreRestarted() {
574 mIsWifiAvailable.reset();
575 mHalClientManager->handleChreRestart();
576 }
577 } // namespace android::hardware::contexthub::common::implementation
578