• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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