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