xref: /aosp_15_r20/system/chre/host/hal_generic/aidl/generic_context_hub_aidl.cc (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2021 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 "generic_context_hub_aidl.h"
18 
19 #include "chre_api/chre/event.h"
20 #include "chre_host/config_util.h"
21 #include "chre_host/file_stream.h"
22 #include "chre_host/fragmented_load_transaction.h"
23 #include "chre_host/host_protocol_host.h"
24 #include "chre_host/log.h"
25 #include "chre_host/napp_header.h"
26 #include "permissions_util.h"
27 
28 #include <algorithm>
29 #include <chrono>
30 #include <limits>
31 
32 namespace aidl::android::hardware::contexthub {
33 
34 // Aliased for consistency with the way these symbols are referenced in
35 // CHRE-side code
36 namespace fbs = ::chre::fbs;
37 
38 using ::android::chre::FragmentedLoadTransaction;
39 using ::android::chre::getPreloadedNanoappsFromConfigFile;
40 using ::android::chre::getStringFromByteVector;
41 using ::android::chre::NanoAppBinaryHeader;
42 using ::android::chre::readFileContents;
43 using ::android::hardware::contexthub::common::implementation::
44     chreToAndroidPermissions;
45 using ::android::hardware::contexthub::common::implementation::
46     kSupportedPermissions;
47 using ::ndk::ScopedAStatus;
48 
49 namespace {
50 constexpr uint32_t kDefaultHubId = 0;
51 constexpr char kPreloadedNanoappsConfigPath[] =
52     "/vendor/etc/chre/preloaded_nanoapps.json";
53 constexpr std::chrono::duration kTestModeTimeout = std::chrono::seconds(10);
54 constexpr uint16_t kMaxValidHostEndPointId = 0x7fff;
55 
56 /*
57  * The starting transaction ID for internal transactions. We choose
58  * the limit + 1 here as any client will only pass non-negative values up to the
59  * limit. The socket connection to CHRE accepts a uint32_t for the transaction
60  * ID, so we can use the value below up to std::numeric_limits<uint32_t>::max()
61  * for internal transaction IDs.
62  */
63 constexpr int32_t kStartingInternalTransactionId = 0x80000000;
64 
extractChreApiMajorVersion(uint32_t chreVersion)65 inline constexpr int8_t extractChreApiMajorVersion(uint32_t chreVersion) {
66   return static_cast<int8_t>(chreVersion >> 24);
67 }
68 
extractChreApiMinorVersion(uint32_t chreVersion)69 inline constexpr int8_t extractChreApiMinorVersion(uint32_t chreVersion) {
70   return static_cast<int8_t>(chreVersion >> 16);
71 }
72 
extractChrePatchVersion(uint32_t chreVersion)73 inline constexpr uint16_t extractChrePatchVersion(uint32_t chreVersion) {
74   return static_cast<uint16_t>(chreVersion);
75 }
76 
getFbsSetting(const Setting & setting,fbs::Setting * fbsSetting)77 bool getFbsSetting(const Setting &setting, fbs::Setting *fbsSetting) {
78   bool foundSetting = true;
79 
80   switch (setting) {
81     case Setting::LOCATION:
82       *fbsSetting = fbs::Setting::LOCATION;
83       break;
84     case Setting::AIRPLANE_MODE:
85       *fbsSetting = fbs::Setting::AIRPLANE_MODE;
86       break;
87     case Setting::MICROPHONE:
88       *fbsSetting = fbs::Setting::MICROPHONE;
89       break;
90     default:
91       foundSetting = false;
92       LOGE("Setting update with invalid enum value %hhu", setting);
93       break;
94   }
95 
96   return foundSetting;
97 }
98 
toServiceSpecificError(bool success)99 ScopedAStatus toServiceSpecificError(bool success) {
100   return success ? ScopedAStatus::ok()
101                  : ScopedAStatus::fromServiceSpecificError(
102                        BnContextHub::EX_CONTEXT_HUB_UNSPECIFIED);
103 }
104 
105 }  // anonymous namespace
106 
getContextHubs(std::vector<ContextHubInfo> * out_contextHubInfos)107 ScopedAStatus ContextHub::getContextHubs(
108     std::vector<ContextHubInfo> *out_contextHubInfos) {
109   ::chre::fbs::HubInfoResponseT response;
110   bool success = mConnection.getContextHubs(&response);
111   if (success) {
112     ContextHubInfo hub;
113     hub.name = getStringFromByteVector(response.name);
114     hub.vendor = getStringFromByteVector(response.vendor);
115     hub.toolchain = getStringFromByteVector(response.toolchain);
116     hub.id = kDefaultHubId;
117     hub.peakMips = response.peak_mips;
118     hub.maxSupportedMessageLengthBytes = response.max_msg_len;
119     hub.chrePlatformId = response.platform_id;
120 
121     uint32_t version = response.chre_platform_version;
122     hub.chreApiMajorVersion = extractChreApiMajorVersion(version);
123     hub.chreApiMinorVersion = extractChreApiMinorVersion(version);
124     hub.chrePatchVersion = extractChrePatchVersion(version);
125 
126     hub.supportedPermissions = kSupportedPermissions;
127 
128     hub.supportsReliableMessages = false;
129 
130     out_contextHubInfos->push_back(hub);
131   }
132 
133   return ndk::ScopedAStatus::ok();
134 }
135 
loadNanoapp(int32_t contextHubId,const NanoappBinary & appBinary,int32_t transactionId)136 ScopedAStatus ContextHub::loadNanoapp(int32_t contextHubId,
137                                       const NanoappBinary &appBinary,
138                                       int32_t transactionId) {
139   if (contextHubId != kDefaultHubId) {
140     LOGE("Invalid ID %" PRId32, contextHubId);
141     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
142   }
143 
144   std::lock_guard<std::mutex> lock(mTestModeMutex);
145   bool success = loadNanoappInternal(appBinary, transactionId);
146   return toServiceSpecificError(success);
147 }
148 
unloadNanoapp(int32_t contextHubId,int64_t appId,int32_t transactionId)149 ScopedAStatus ContextHub::unloadNanoapp(int32_t contextHubId, int64_t appId,
150                                         int32_t transactionId) {
151   if (contextHubId != kDefaultHubId) {
152     LOGE("Invalid ID %" PRId32, contextHubId);
153     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
154   }
155 
156   std::lock_guard<std::mutex> lock(mTestModeMutex);
157   bool success = unloadNanoappInternal(appId, transactionId);
158   return toServiceSpecificError(success);
159 }
160 
disableNanoapp(int32_t,int64_t appId,int32_t)161 ScopedAStatus ContextHub::disableNanoapp(int32_t /* contextHubId */,
162                                          int64_t appId,
163                                          int32_t /* transactionId */) {
164   LOGW("Attempted to disable app ID 0x%016" PRIx64 ", but not supported",
165        appId);
166   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
167 }
168 
enableNanoapp(int32_t,int64_t appId,int32_t)169 ScopedAStatus ContextHub::enableNanoapp(int32_t /* contextHubId */,
170                                         int64_t appId,
171                                         int32_t /* transactionId */) {
172   LOGW("Attempted to enable app ID 0x%016" PRIx64 ", but not supported", appId);
173   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
174 }
175 
onSettingChanged(Setting setting,bool enabled)176 ScopedAStatus ContextHub::onSettingChanged(Setting setting, bool enabled) {
177   mSettingEnabled[setting] = enabled;
178   fbs::Setting fbsSetting;
179   bool isWifiOrBtSetting =
180       (setting == Setting::WIFI_MAIN || setting == Setting::WIFI_SCANNING ||
181        setting == Setting::BT_MAIN || setting == Setting::BT_SCANNING);
182 
183   if (!isWifiOrBtSetting && getFbsSetting(setting, &fbsSetting)) {
184     mConnection.sendSettingChangedNotification(fbsSetting,
185                                                toFbsSettingState(enabled));
186   }
187 
188   bool isWifiMainEnabled = isSettingEnabled(Setting::WIFI_MAIN);
189   bool isWifiScanEnabled = isSettingEnabled(Setting::WIFI_SCANNING);
190   bool isAirplaneModeEnabled = isSettingEnabled(Setting::AIRPLANE_MODE);
191 
192   // Because the airplane mode impact on WiFi is not standardized in Android,
193   // we write a specific handling in the Context Hub HAL to inform CHRE.
194   // The following definition is a default one, and can be adjusted
195   // appropriately if necessary.
196   bool isWifiAvailable = isAirplaneModeEnabled
197                              ? (isWifiMainEnabled)
198                              : (isWifiMainEnabled || isWifiScanEnabled);
199   if (!mIsWifiAvailable.has_value() || (isWifiAvailable != mIsWifiAvailable)) {
200     mConnection.sendSettingChangedNotification(
201         fbs::Setting::WIFI_AVAILABLE, toFbsSettingState(isWifiAvailable));
202     mIsWifiAvailable = isWifiAvailable;
203   }
204 
205   // The BT switches determine whether we can BLE scan which is why things are
206   // mapped like this into CHRE.
207   bool isBtMainEnabled = isSettingEnabled(Setting::BT_MAIN);
208   bool isBtScanEnabled = isSettingEnabled(Setting::BT_SCANNING);
209   bool isBleAvailable = isBtMainEnabled || isBtScanEnabled;
210   if (!mIsBleAvailable.has_value() || (isBleAvailable != mIsBleAvailable)) {
211     mConnection.sendSettingChangedNotification(
212         fbs::Setting::BLE_AVAILABLE, toFbsSettingState(isBleAvailable));
213     mIsBleAvailable = isBleAvailable;
214   }
215 
216   return ndk::ScopedAStatus::ok();
217 }
218 
queryNanoapps(int32_t contextHubId)219 ScopedAStatus ContextHub::queryNanoapps(int32_t contextHubId) {
220   if (contextHubId != kDefaultHubId) {
221     LOGE("Invalid ID %" PRId32, contextHubId);
222     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
223   }
224   return toServiceSpecificError(mConnection.queryNanoapps());
225 }
226 
getPreloadedNanoappIds(int32_t contextHubId,std::vector<int64_t> * out_preloadedNanoappIds)227 ::ndk::ScopedAStatus ContextHub::getPreloadedNanoappIds(
228     int32_t contextHubId, std::vector<int64_t> *out_preloadedNanoappIds) {
229   if (contextHubId != kDefaultHubId) {
230     LOGE("Invalid ID %" PRId32, contextHubId);
231     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
232   }
233 
234   if (out_preloadedNanoappIds == nullptr) {
235     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
236   }
237 
238   std::unique_lock<std::mutex> lock(mPreloadedNanoappIdsMutex);
239   if (mPreloadedNanoappIds.has_value()) {
240     *out_preloadedNanoappIds = *mPreloadedNanoappIds;
241     return ScopedAStatus::ok();
242   }
243 
244   std::vector<chrePreloadedNanoappInfo> preloadedNanoapps;
245   if (!getPreloadedNanoappIdsFromConfigFile(preloadedNanoapps, nullptr)) {
246     return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
247   }
248 
249   mPreloadedNanoappIds = std::vector<int64_t>();
250   for (const auto &preloadedNanoapp : preloadedNanoapps) {
251     mPreloadedNanoappIds->push_back(preloadedNanoapp.id);
252     out_preloadedNanoappIds->push_back(preloadedNanoapp.id);
253   }
254 
255   return ScopedAStatus::ok();
256 }
257 
registerCallback(int32_t contextHubId,const std::shared_ptr<IContextHubCallback> & cb)258 ScopedAStatus ContextHub::registerCallback(
259     int32_t contextHubId, const std::shared_ptr<IContextHubCallback> &cb) {
260   if (contextHubId != kDefaultHubId) {
261     LOGE("Invalid ID %" PRId32, contextHubId);
262     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
263   }
264   std::lock_guard<std::mutex> lock(mCallbackMutex);
265   if (mCallback != nullptr) {
266     binder_status_t binder_status = AIBinder_unlinkToDeath(
267         mCallback->asBinder().get(), mDeathRecipient.get(), this);
268     if (binder_status != STATUS_OK) {
269       LOGE("Failed to unlink to death");
270     }
271   }
272   mCallback = cb;
273   if (cb != nullptr) {
274     binder_status_t binder_status =
275         AIBinder_linkToDeath(cb->asBinder().get(), mDeathRecipient.get(), this);
276     if (binder_status != STATUS_OK) {
277       LOGE("Failed to link to death");
278     }
279   }
280   return ScopedAStatus::ok();
281 }
282 
sendMessageToHub(int32_t contextHubId,const ContextHubMessage & message)283 ScopedAStatus ContextHub::sendMessageToHub(int32_t contextHubId,
284                                            const ContextHubMessage &message) {
285   if (contextHubId != kDefaultHubId) {
286     LOGE("Invalid ID %" PRId32, contextHubId);
287     return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
288   }
289 
290   bool success = mConnection.sendMessageToHub(
291       message.nanoappId, message.messageType, message.hostEndPoint,
292       message.messageBody.data(), message.messageBody.size());
293   mEventLogger.logMessageToNanoapp(message, success);
294 
295   return toServiceSpecificError(success);
296 }
297 
setTestMode(bool enable)298 ScopedAStatus ContextHub::setTestMode(bool enable) {
299   return enable ? enableTestMode() : disableTestMode();
300 }
301 
sendMessageDeliveryStatusToHub(int32_t,const MessageDeliveryStatus &)302 ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
303     int32_t /* contextHubId */,
304     const MessageDeliveryStatus & /* messageDeliveryStatus */) {
305   return ndk::ScopedAStatus::ok();
306 }
307 
onHostEndpointConnected(const HostEndpointInfo & in_info)308 ScopedAStatus ContextHub::onHostEndpointConnected(
309     const HostEndpointInfo &in_info) {
310   std::lock_guard<std::mutex> lock(mConnectedHostEndpointsMutex);
311   uint8_t type;
312   switch (in_info.type) {
313     case HostEndpointInfo::Type::APP:
314       type = CHRE_HOST_ENDPOINT_TYPE_APP;
315       break;
316     case HostEndpointInfo::Type::NATIVE:
317       type = CHRE_HOST_ENDPOINT_TYPE_NATIVE;
318       break;
319     case HostEndpointInfo::Type::FRAMEWORK:
320       type = CHRE_HOST_ENDPOINT_TYPE_FRAMEWORK;
321       break;
322     default:
323       LOGE("Unsupported host endpoint type %" PRIu32, type);
324       return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
325   }
326   mConnectedHostEndpoints.insert(in_info.hostEndpointId);
327   mConnection.onHostEndpointConnected(
328       in_info.hostEndpointId, type, in_info.packageName.value_or(std::string()),
329       in_info.attributionTag.value_or(std::string()));
330   return ndk::ScopedAStatus::ok();
331 }
332 
onHostEndpointDisconnected(char16_t in_hostEndpointId)333 ScopedAStatus ContextHub::onHostEndpointDisconnected(
334     char16_t in_hostEndpointId) {
335   std::lock_guard<std::mutex> lock(mConnectedHostEndpointsMutex);
336   if (mConnectedHostEndpoints.count(in_hostEndpointId) > 0) {
337     mConnectedHostEndpoints.erase(in_hostEndpointId);
338 
339     mConnection.onHostEndpointDisconnected(in_hostEndpointId);
340   } else {
341     LOGE("Unknown host endpoint disconnected (ID: %" PRIu16 ")",
342          in_hostEndpointId);
343   }
344 
345   return ndk::ScopedAStatus::ok();
346 }
347 
onNanSessionStateChanged(const NanSessionStateUpdate &)348 ScopedAStatus ContextHub::onNanSessionStateChanged(
349     const NanSessionStateUpdate & /*in_update*/) {
350   // TODO(271471342): Add support for NAN session management.
351   return ndk::ScopedAStatus::ok();
352 }
353 
getHubs(std::vector<HubInfo> * hubs)354 ScopedAStatus ContextHub::getHubs(std::vector<HubInfo> *hubs) {
355   if (mV4Impl) return mV4Impl->getHubs(hubs);
356   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
357 }
358 
getEndpoints(std::vector<EndpointInfo> * endpoints)359 ScopedAStatus ContextHub::getEndpoints(std::vector<EndpointInfo> *endpoints) {
360   if (mV4Impl) return mV4Impl->getEndpoints(endpoints);
361   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
362 }
363 
registerEndpoint(const EndpointInfo & endpoint)364 ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo &endpoint) {
365   if (mV4Impl) return mV4Impl->registerEndpoint(endpoint);
366   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
367 }
368 
unregisterEndpoint(const EndpointInfo & endpoint)369 ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo &endpoint) {
370   if (mV4Impl) return mV4Impl->unregisterEndpoint(endpoint);
371   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
372 }
373 
registerEndpointCallback(const std::shared_ptr<IEndpointCallback> & callback)374 ScopedAStatus ContextHub::registerEndpointCallback(
375     const std::shared_ptr<IEndpointCallback> &callback) {
376   if (mV4Impl) return mV4Impl->registerEndpointCallback(callback);
377   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
378 }
379 
requestSessionIdRange(int32_t size,std::vector<int32_t> * ids)380 ScopedAStatus ContextHub::requestSessionIdRange(int32_t size,
381                                                 std::vector<int32_t> *ids) {
382   if (mV4Impl) return mV4Impl->requestSessionIdRange(size, ids);
383   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
384 }
385 
openEndpointSession(int32_t sessionId,const EndpointId & destination,const EndpointId & initiator,const std::optional<std::string> & serviceDescriptor)386 ScopedAStatus ContextHub::openEndpointSession(
387     int32_t sessionId, const EndpointId &destination,
388     const EndpointId &initiator,
389     const std::optional<std::string> &serviceDescriptor) {
390   if (mV4Impl) {
391     return mV4Impl->openEndpointSession(sessionId, destination, initiator,
392                                         serviceDescriptor);
393   }
394   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
395 }
396 
sendMessageToEndpoint(int32_t sessionId,const Message & msg)397 ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t sessionId,
398                                                 const Message &msg) {
399   if (mV4Impl) return mV4Impl->sendMessageToEndpoint(sessionId, msg);
400   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
401 }
402 
sendMessageDeliveryStatusToEndpoint(int32_t sessionId,const MessageDeliveryStatus & msgStatus)403 ScopedAStatus ContextHub::sendMessageDeliveryStatusToEndpoint(
404     int32_t sessionId, const MessageDeliveryStatus &msgStatus) {
405   if (mV4Impl)
406     return mV4Impl->sendMessageDeliveryStatusToEndpoint(sessionId, msgStatus);
407   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
408 }
409 
closeEndpointSession(int32_t sessionId,Reason reason)410 ScopedAStatus ContextHub::closeEndpointSession(int32_t sessionId,
411                                                Reason reason) {
412   if (mV4Impl) return mV4Impl->closeEndpointSession(sessionId, reason);
413   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
414 }
415 
endpointSessionOpenComplete(int32_t sessionId)416 ScopedAStatus ContextHub::endpointSessionOpenComplete(int32_t sessionId) {
417   if (mV4Impl) return mV4Impl->endpointSessionOpenComplete(sessionId);
418   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
419 }
420 
onNanoappMessage(const::chre::fbs::NanoappMessageT & message)421 void ContextHub::onNanoappMessage(const ::chre::fbs::NanoappMessageT &message) {
422   std::lock_guard<std::mutex> lock(mCallbackMutex);
423   if (mCallback != nullptr) {
424     if (message.host_endpoint > kMaxValidHostEndPointId &&
425         message.host_endpoint != CHRE_HOST_ENDPOINT_BROADCAST) {
426       return;
427     }
428 
429     mEventLogger.logMessageFromNanoapp(message);
430     ContextHubMessage outMessage;
431     outMessage.nanoappId = message.app_id;
432     outMessage.hostEndPoint = message.host_endpoint;
433     outMessage.messageType = message.message_type;
434     outMessage.messageBody = message.message;
435     outMessage.permissions = chreToAndroidPermissions(message.permissions);
436 
437     std::vector<std::string> messageContentPerms =
438         chreToAndroidPermissions(message.message_permissions);
439     mCallback->handleContextHubMessage(outMessage, messageContentPerms);
440   }
441 }
442 
onNanoappListResponse(const::chre::fbs::NanoappListResponseT & response)443 void ContextHub::onNanoappListResponse(
444     const ::chre::fbs::NanoappListResponseT &response) {
445   std::vector<NanoappInfo> appInfoList;
446   for (const std::unique_ptr<::chre::fbs::NanoappListEntryT> &nanoapp :
447        response.nanoapps) {
448     // TODO(b/245202050): determine if this is really required, and if so, have
449     // HostProtocolHost strip out null entries as part of decode
450     if (nanoapp == nullptr) {
451       continue;
452     }
453 
454     LOGV("App 0x%016" PRIx64 " ver 0x%" PRIx32 " permissions 0x%" PRIx32
455          " enabled %d system %d",
456          nanoapp->app_id, nanoapp->version, nanoapp->permissions,
457          nanoapp->enabled, nanoapp->is_system);
458     if (!nanoapp->is_system) {
459       NanoappInfo appInfo;
460 
461       appInfo.nanoappId = nanoapp->app_id;
462       appInfo.nanoappVersion = nanoapp->version;
463       appInfo.enabled = nanoapp->enabled;
464       appInfo.permissions = chreToAndroidPermissions(nanoapp->permissions);
465 
466       std::vector<NanoappRpcService> rpcServices;
467       for (const auto &service : nanoapp->rpc_services) {
468         NanoappRpcService aidlService;
469         aidlService.id = service->id;
470         aidlService.version = service->version;
471         rpcServices.emplace_back(aidlService);
472       }
473       appInfo.rpcServices = rpcServices;
474 
475       appInfoList.push_back(appInfo);
476     }
477   }
478 
479   {
480     std::lock_guard<std::mutex> lock(mQueryNanoappsInternalMutex);
481     if (!mQueryNanoappsInternalList) {
482       mQueryNanoappsInternalList = appInfoList;
483       mQueryNanoappsInternalCondVar.notify_all();
484     }
485   }
486 
487   std::lock_guard<std::mutex> lock(mCallbackMutex);
488   if (mCallback != nullptr) {
489     mCallback->handleNanoappInfo(appInfoList);
490   }
491 }
492 
onTransactionResult(uint32_t transactionId,bool success)493 void ContextHub::onTransactionResult(uint32_t transactionId, bool success) {
494   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
495   if (mSynchronousLoadUnloadTransactionId &&
496       transactionId == *mSynchronousLoadUnloadTransactionId) {
497     mSynchronousLoadUnloadSuccess = success;
498     mSynchronousLoadUnloadCondVar.notify_all();
499   } else {
500     std::lock_guard<std::mutex> callbackLock(mCallbackMutex);
501     if (mCallback != nullptr) {
502       mCallback->handleTransactionResult(transactionId, success);
503     }
504   }
505 }
506 
onContextHubRestarted()507 void ContextHub::onContextHubRestarted() {
508   std::lock_guard<std::mutex> lock(mCallbackMutex);
509   mIsWifiAvailable.reset();
510   {
511     std::lock_guard<std::mutex> endpointLock(mConnectedHostEndpointsMutex);
512     mConnectedHostEndpoints.clear();
513     mEventLogger.logContextHubRestart();
514   }
515   if (mCallback != nullptr) {
516     mCallback->handleContextHubAsyncEvent(AsyncEventType::RESTARTED);
517   }
518 }
519 
onDebugDumpData(const::chre::fbs::DebugDumpDataT & data)520 void ContextHub::onDebugDumpData(const ::chre::fbs::DebugDumpDataT &data) {
521   auto str = std::string(reinterpret_cast<const char *>(data.debug_str.data()),
522                          data.debug_str.size());
523   debugDumpAppend(str);
524 }
525 
onDebugDumpComplete(const::chre::fbs::DebugDumpResponseT &)526 void ContextHub::onDebugDumpComplete(
527     const ::chre::fbs::DebugDumpResponseT & /* response */) {
528   debugDumpComplete();
529 }
530 
onContextHubV4Message(const::chre::fbs::ChreMessageUnion & message)531 bool ContextHub::onContextHubV4Message(
532     const ::chre::fbs::ChreMessageUnion &message) {
533   if (mV4Impl) return mV4Impl->handleMessageFromChre(message);
534   return false;
535 }
536 
handleServiceDeath()537 void ContextHub::handleServiceDeath() {
538   LOGI("Context Hub Service died ...");
539   {
540     std::lock_guard<std::mutex> lock(mCallbackMutex);
541     mCallback.reset();
542   }
543   {
544     std::lock_guard<std::mutex> lock(mConnectedHostEndpointsMutex);
545     mConnectedHostEndpoints.clear();
546   }
547 }
548 
onServiceDied(void * cookie)549 void ContextHub::onServiceDied(void *cookie) {
550   auto *contexthub = static_cast<ContextHub *>(cookie);
551   contexthub->handleServiceDeath();
552 }
553 
dump(int fd,const char **,uint32_t)554 binder_status_t ContextHub::dump(int fd, const char ** /* args */,
555                                  uint32_t /* numArgs */) {
556   debugDumpStart(fd);
557   debugDumpFinish();
558   return STATUS_OK;
559 }
560 
debugDumpFinish()561 void ContextHub::debugDumpFinish() {
562   if (checkDebugFd()) {
563     const std::string &dump = mEventLogger.dump();
564     writeToDebugFile(dump.c_str());
565     writeToDebugFile("\n-- End of CHRE/ASH debug info --\n");
566     invalidateDebugFd();
567   }
568 }
569 
writeToDebugFile(const char * str)570 void ContextHub::writeToDebugFile(const char *str) {
571   if (!::android::base::WriteStringToFd(std::string(str), getDebugFd())) {
572     LOGW("Failed to write %zu bytes to debug dump fd", strlen(str));
573   }
574 }
575 
enableTestMode()576 ScopedAStatus ContextHub::enableTestMode() {
577   std::unique_lock<std::mutex> lock(mTestModeMutex);
578 
579   bool success = false;
580   std::vector<int64_t> loadedNanoappIds;
581   std::vector<int64_t> preloadedNanoappIds;
582   std::vector<int64_t> nanoappIdsToUnload;
583   if (mIsTestModeEnabled) {
584     success = true;
585   } else if (mConnection.isLoadTransactionPending()) {
586     /**
587      * There is already a pending load transaction. We cannot change the test
588      * mode state if there is a pending load transaction. We do not consider
589      * pending unload transactions as they can happen asynchronously and
590      * multiple at a time.
591      */
592     LOGE("There exists a pending load transaction. Cannot enable test mode.");
593   } else if (!queryNanoappsInternal(kDefaultHubId, &loadedNanoappIds)) {
594     LOGE("Could not query nanoapps to enable test mode.");
595   } else if (!getPreloadedNanoappIds(kDefaultHubId, &preloadedNanoappIds)
596                   .isOk()) {
597     LOGE("Unable to get preloaded nanoapp IDs from the config file.");
598   } else {
599     std::sort(loadedNanoappIds.begin(), loadedNanoappIds.end());
600     std::sort(preloadedNanoappIds.begin(), preloadedNanoappIds.end());
601 
602     // Calculate the system nanoapp IDs. They are preloaded, but not loaded.
603     mSystemNanoappIds.clear();
604     std::set_difference(preloadedNanoappIds.begin(), preloadedNanoappIds.end(),
605                         loadedNanoappIds.begin(), loadedNanoappIds.end(),
606                         std::back_inserter(mSystemNanoappIds));
607 
608     /*
609      * Unload all preloaded and loaded nanoapps (set intersection).
610      * Both vectors need to be sorted for std::set_intersection to work.
611      * We explicitly choose not to use std::set here to avoid the
612      * copying cost as well as the tree balancing cost for the
613      * red-black tree.
614      */
615     std::set_intersection(loadedNanoappIds.begin(), loadedNanoappIds.end(),
616                           preloadedNanoappIds.begin(),
617                           preloadedNanoappIds.end(),
618                           std::back_inserter(nanoappIdsToUnload));
619     if (!unloadNanoappsInternal(kDefaultHubId, nanoappIdsToUnload)) {
620       LOGE("Unable to unload all loaded and preloaded nanoapps.");
621     }
622     success = true;
623   }
624 
625   if (success) {
626     mIsTestModeEnabled = true;
627     LOGI("Successfully enabled test mode.");
628     return ScopedAStatus::ok();
629   } else {
630     return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
631   }
632 }
633 
disableTestMode()634 ScopedAStatus ContextHub::disableTestMode() {
635   std::unique_lock<std::mutex> lock(mTestModeMutex);
636 
637   bool success = false;
638   std::vector<chrePreloadedNanoappInfo> preloadedNanoapps;
639   std::string preloadedNanoappDirectory;
640   if (!mIsTestModeEnabled) {
641     success = true;
642   } else if (mConnection.isLoadTransactionPending()) {
643     /**
644      * There is already a pending load transaction. We cannot change the test
645      * mode state if there is a pending load transaction. We do not consider
646      * pending unload transactions as they can happen asynchronously and
647      * multiple at a time.
648      */
649     LOGE("There exists a pending load transaction. Cannot disable test mode.");
650   } else if (!getPreloadedNanoappIdsFromConfigFile(
651                  preloadedNanoapps, &preloadedNanoappDirectory)) {
652     LOGE("Unable to get preloaded nanoapp IDs from the config file.");
653   } else {
654     std::vector<NanoappBinary> nanoappsToLoad = selectPreloadedNanoappsToLoad(
655         preloadedNanoapps, preloadedNanoappDirectory);
656 
657     if (!loadNanoappsInternal(kDefaultHubId, nanoappsToLoad)) {
658       LOGE("Unable to load all preloaded, non-system nanoapps.");
659     }
660     // Any attempt to load non-test nanoapps should disable test mode, even if
661     // not all nanoapps are successfully loaded.
662     success = true;
663   }
664 
665   if (success) {
666     mIsTestModeEnabled = false;
667     LOGI("Successfully disabled test mode.");
668     return ScopedAStatus::ok();
669   } else {
670     return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
671   }
672 }
673 
queryNanoappsInternal(int32_t contextHubId,std::vector<int64_t> * nanoappIdList)674 bool ContextHub::queryNanoappsInternal(int32_t contextHubId,
675                                        std::vector<int64_t> *nanoappIdList) {
676   if (contextHubId != kDefaultHubId) {
677     LOGE("Invalid ID %" PRId32, contextHubId);
678     return false;
679   }
680 
681   std::unique_lock<std::mutex> lock(mQueryNanoappsInternalMutex);
682   mQueryNanoappsInternalList.reset();
683 
684   bool success =
685       queryNanoapps(contextHubId).isOk() &&
686       mQueryNanoappsInternalCondVar.wait_for(lock, kTestModeTimeout, [this]() {
687         return mQueryNanoappsInternalList.has_value();
688       });
689   if (success && nanoappIdList != nullptr) {
690     std::transform(
691         mQueryNanoappsInternalList->begin(), mQueryNanoappsInternalList->end(),
692         std::back_inserter(*nanoappIdList),
693         [](const NanoappInfo &nanoapp) { return nanoapp.nanoappId; });
694   }
695   return success;
696 }
697 
loadNanoappInternal(const NanoappBinary & appBinary,int32_t transactionId)698 bool ContextHub::loadNanoappInternal(const NanoappBinary &appBinary,
699                                      int32_t transactionId) {
700   uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
701                               (appBinary.targetChreApiMinorVersion << 16);
702   FragmentedLoadTransaction transaction(
703       transactionId, appBinary.nanoappId, appBinary.nanoappVersion,
704       appBinary.flags, targetApiVersion, appBinary.customBinary);
705   bool success = mConnection.loadNanoapp(transaction);
706   mEventLogger.logNanoappLoad(appBinary.nanoappId,
707                               appBinary.customBinary.size(),
708                               appBinary.nanoappVersion, success);
709   return success;
710 }
711 
loadNanoappsInternal(int32_t contextHubId,const std::vector<NanoappBinary> & nanoappBinaryList)712 bool ContextHub::loadNanoappsInternal(
713     int32_t contextHubId, const std::vector<NanoappBinary> &nanoappBinaryList) {
714   if (contextHubId != kDefaultHubId) {
715     LOGE("Invalid ID %" PRId32, contextHubId);
716     return false;
717   }
718 
719   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
720   mSynchronousLoadUnloadTransactionId = kStartingInternalTransactionId;
721 
722   for (const NanoappBinary &nanoappToLoad : nanoappBinaryList) {
723     LOGI("Loading nanoapp with ID: 0x%016" PRIx64, nanoappToLoad.nanoappId);
724 
725     bool success = false;
726     if (!loadNanoappInternal(nanoappToLoad,
727                              *mSynchronousLoadUnloadTransactionId)) {
728       LOGE("Failed to request loading nanoapp with ID 0x%" PRIx64,
729            nanoappToLoad.nanoappId);
730     } else {
731       mSynchronousLoadUnloadSuccess.reset();
732       mSynchronousLoadUnloadCondVar.wait_for(lock, kTestModeTimeout, [this]() {
733         return mSynchronousLoadUnloadSuccess.has_value();
734       });
735       if (mSynchronousLoadUnloadSuccess.has_value() &&
736           *mSynchronousLoadUnloadSuccess) {
737         LOGI("Successfully loaded nanoapp with ID: 0x%016" PRIx64,
738              nanoappToLoad.nanoappId);
739         success = true;
740       }
741     }
742 
743     if (!success) {
744       LOGE("Failed to load nanoapp with ID 0x%" PRIx64,
745            nanoappToLoad.nanoappId);
746     }
747     ++(*mSynchronousLoadUnloadTransactionId);
748   }
749 
750   return true;
751 }
752 
unloadNanoappInternal(int64_t appId,int32_t transactionId)753 bool ContextHub::unloadNanoappInternal(int64_t appId, int32_t transactionId) {
754   bool success = mConnection.unloadNanoapp(appId, transactionId);
755   mEventLogger.logNanoappUnload(appId, success);
756   return success;
757 }
758 
unloadNanoappsInternal(int32_t contextHubId,const std::vector<int64_t> & nanoappIdList)759 bool ContextHub::unloadNanoappsInternal(
760     int32_t contextHubId, const std::vector<int64_t> &nanoappIdList) {
761   if (contextHubId != kDefaultHubId) {
762     LOGE("Invalid ID %" PRId32, contextHubId);
763     return false;
764   }
765 
766   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
767   mSynchronousLoadUnloadTransactionId = kStartingInternalTransactionId;
768 
769   for (int64_t nanoappIdToUnload : nanoappIdList) {
770     LOGI("Unloading nanoapp with ID: 0x%016" PRIx64, nanoappIdToUnload);
771 
772     bool success = false;
773     if (!unloadNanoappInternal(nanoappIdToUnload,
774                                *mSynchronousLoadUnloadTransactionId)) {
775       LOGE("Failed to request unloading nanoapp with ID 0x%" PRIx64,
776            nanoappIdToUnload);
777     } else {
778       mSynchronousLoadUnloadSuccess.reset();
779       mSynchronousLoadUnloadCondVar.wait_for(lock, kTestModeTimeout, [this]() {
780         return mSynchronousLoadUnloadSuccess.has_value();
781       });
782       if (mSynchronousLoadUnloadSuccess.has_value() &&
783           *mSynchronousLoadUnloadSuccess) {
784         LOGI("Successfully unloaded nanoapp with ID: 0x%016" PRIx64,
785              nanoappIdToUnload);
786 
787         success = true;
788       }
789     }
790 
791     if (!success) {
792       LOGE("Failed to unload nanoapp with ID 0x%" PRIx64, nanoappIdToUnload);
793     }
794     ++(*mSynchronousLoadUnloadTransactionId);
795   }
796 
797   return true;
798 }
799 
getPreloadedNanoappIdsFromConfigFile(std::vector<chrePreloadedNanoappInfo> & out_preloadedNanoapps,std::string * out_directory) const800 bool ContextHub::getPreloadedNanoappIdsFromConfigFile(
801     std::vector<chrePreloadedNanoappInfo> &out_preloadedNanoapps,
802     std::string *out_directory) const {
803   std::vector<std::string> nanoappNames;
804   std::string directory;
805 
806   bool success = getPreloadedNanoappsFromConfigFile(
807       kPreloadedNanoappsConfigPath, directory, nanoappNames);
808   if (!success) {
809     LOGE("Failed to parse preloaded nanoapps config file");
810   }
811 
812   for (const std::string &nanoappName : nanoappNames) {
813     std::string headerFile = directory + "/" + nanoappName + ".napp_header";
814     std::vector<uint8_t> headerBuffer;
815     if (!readFileContents(headerFile.c_str(), headerBuffer)) {
816       LOGE("Cannot read header file: %s", headerFile.c_str());
817       continue;
818     }
819 
820     if (headerBuffer.size() != sizeof(NanoAppBinaryHeader)) {
821       LOGE("Header size mismatch");
822       continue;
823     }
824 
825     const auto *appHeader =
826         reinterpret_cast<const NanoAppBinaryHeader *>(headerBuffer.data());
827     out_preloadedNanoapps.emplace_back(static_cast<int64_t>(appHeader->appId),
828                                        nanoappName, *appHeader);
829   }
830 
831   if (out_directory != nullptr) {
832     *out_directory = directory;
833   }
834 
835   return true;
836 }
837 
selectPreloadedNanoappsToLoad(std::vector<chrePreloadedNanoappInfo> & preloadedNanoapps,const std::string & preloadedNanoappDirectory)838 std::vector<NanoappBinary> ContextHub::selectPreloadedNanoappsToLoad(
839     std::vector<chrePreloadedNanoappInfo> &preloadedNanoapps,
840     const std::string &preloadedNanoappDirectory) {
841   std::vector<NanoappBinary> nanoappsToLoad;
842 
843   for (auto &preloadedNanoapp : preloadedNanoapps) {
844     int64_t nanoappId = preloadedNanoapp.id;
845 
846     // A nanoapp is a system nanoapp if it is in the preloaded nanoapp list
847     // but not in the loaded nanoapp list as CHRE hides system nanoapps
848     // from the HAL.
849     bool isSystemNanoapp =
850         std::any_of(mSystemNanoappIds.begin(), mSystemNanoappIds.end(),
851                     [nanoappId](int64_t systemNanoappId) {
852                       return systemNanoappId == nanoappId;
853                     });
854     if (!isSystemNanoapp) {
855       std::vector<uint8_t> nanoappBuffer;
856       std::string nanoappFile =
857           preloadedNanoappDirectory + "/" + preloadedNanoapp.name + ".so";
858       if (!readFileContents(nanoappFile.c_str(), nanoappBuffer)) {
859         LOGE("Cannot read header file: %s", nanoappFile.c_str());
860       } else {
861         NanoappBinary nanoapp;
862         nanoapp.nanoappId = preloadedNanoapp.header.appId;
863         nanoapp.nanoappVersion = preloadedNanoapp.header.appVersion;
864         nanoapp.flags = preloadedNanoapp.header.flags;
865         nanoapp.targetChreApiMajorVersion =
866             preloadedNanoapp.header.targetChreApiMajorVersion;
867         nanoapp.targetChreApiMinorVersion =
868             preloadedNanoapp.header.targetChreApiMinorVersion;
869         nanoapp.customBinary = nanoappBuffer;
870 
871         nanoappsToLoad.push_back(nanoapp);
872       }
873     }
874   }
875   return nanoappsToLoad;
876 }
877 
878 }  // namespace aidl::android::hardware::contexthub
879