• 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 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 
registerEndpointHub(const std::shared_ptr<IEndpointCallback> & callback,const HubInfo & hubInfo,std::shared_ptr<IEndpointCommunication> * hubInterface)364 ScopedAStatus ContextHub::registerEndpointHub(
365     const std::shared_ptr<IEndpointCallback> &callback, const HubInfo &hubInfo,
366     std::shared_ptr<IEndpointCommunication> *hubInterface) {
367   if (mV4Impl)
368     return mV4Impl->registerEndpointHub(callback, hubInfo, hubInterface);
369   return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
370 }
371 
onNanoappMessage(const::chre::fbs::NanoappMessageT & message)372 void ContextHub::onNanoappMessage(const ::chre::fbs::NanoappMessageT &message) {
373   std::lock_guard<std::mutex> lock(mCallbackMutex);
374   if (mCallback != nullptr) {
375     if (message.host_endpoint > kMaxValidHostEndPointId &&
376         message.host_endpoint != CHRE_HOST_ENDPOINT_BROADCAST) {
377       return;
378     }
379 
380     mEventLogger.logMessageFromNanoapp(message);
381     ContextHubMessage outMessage;
382     outMessage.nanoappId = message.app_id;
383     outMessage.hostEndPoint = message.host_endpoint;
384     outMessage.messageType = message.message_type;
385     outMessage.messageBody = message.message;
386     outMessage.permissions = chreToAndroidPermissions(message.permissions);
387 
388     std::vector<std::string> messageContentPerms =
389         chreToAndroidPermissions(message.message_permissions);
390     mCallback->handleContextHubMessage(outMessage, messageContentPerms);
391   }
392 }
393 
onNanoappListResponse(const::chre::fbs::NanoappListResponseT & response)394 void ContextHub::onNanoappListResponse(
395     const ::chre::fbs::NanoappListResponseT &response) {
396   std::vector<NanoappInfo> appInfoList;
397   for (const std::unique_ptr<::chre::fbs::NanoappListEntryT> &nanoapp :
398        response.nanoapps) {
399     // TODO(b/245202050): determine if this is really required, and if so, have
400     // HostProtocolHost strip out null entries as part of decode
401     if (nanoapp == nullptr) {
402       continue;
403     }
404 
405     LOGV("App 0x%016" PRIx64 " ver 0x%" PRIx32 " permissions 0x%" PRIx32
406          " enabled %d system %d",
407          nanoapp->app_id, nanoapp->version, nanoapp->permissions,
408          nanoapp->enabled, nanoapp->is_system);
409     if (!nanoapp->is_system) {
410       NanoappInfo appInfo;
411 
412       appInfo.nanoappId = nanoapp->app_id;
413       appInfo.nanoappVersion = nanoapp->version;
414       appInfo.enabled = nanoapp->enabled;
415       appInfo.permissions = chreToAndroidPermissions(nanoapp->permissions);
416 
417       std::vector<NanoappRpcService> rpcServices;
418       for (const auto &service : nanoapp->rpc_services) {
419         NanoappRpcService aidlService;
420         aidlService.id = service->id;
421         aidlService.version = service->version;
422         rpcServices.emplace_back(aidlService);
423       }
424       appInfo.rpcServices = rpcServices;
425 
426       appInfoList.push_back(appInfo);
427     }
428   }
429 
430   {
431     std::lock_guard<std::mutex> lock(mQueryNanoappsInternalMutex);
432     if (!mQueryNanoappsInternalList) {
433       mQueryNanoappsInternalList = appInfoList;
434       mQueryNanoappsInternalCondVar.notify_all();
435       // This was an internal HAL request - do not call callback
436       return;
437     }
438   }
439 
440   std::lock_guard<std::mutex> lock(mCallbackMutex);
441   if (mCallback != nullptr) {
442     mCallback->handleNanoappInfo(appInfoList);
443   }
444 }
445 
onTransactionResult(uint32_t transactionId,bool success)446 void ContextHub::onTransactionResult(uint32_t transactionId, bool success) {
447   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
448   if (mSynchronousLoadUnloadTransactionId &&
449       transactionId == *mSynchronousLoadUnloadTransactionId) {
450     mSynchronousLoadUnloadSuccess = success;
451     mSynchronousLoadUnloadCondVar.notify_all();
452   } else {
453     std::lock_guard<std::mutex> callbackLock(mCallbackMutex);
454     if (mCallback != nullptr) {
455       mCallback->handleTransactionResult(transactionId, success);
456     }
457   }
458 }
459 
onContextHubConnected(bool restart)460 void ContextHub::onContextHubConnected(bool restart) {
461   // Handle any initialization on the first CHRE connection.
462   if (!restart) {
463     if (mV4Impl) mV4Impl->init();
464     return;
465   }
466 
467   if (mV4Impl) {
468     mV4Impl->onChreDisconnected();
469     mV4Impl->onChreRestarted();
470   }
471 
472   std::lock_guard<std::mutex> lock(mCallbackMutex);
473   mIsWifiAvailable.reset();
474   {
475     std::lock_guard<std::mutex> endpointLock(mConnectedHostEndpointsMutex);
476     mConnectedHostEndpoints.clear();
477     mEventLogger.logContextHubRestart();
478   }
479   if (mCallback != nullptr) {
480     mCallback->handleContextHubAsyncEvent(AsyncEventType::RESTARTED);
481   }
482 }
483 
onDebugDumpData(const::chre::fbs::DebugDumpDataT & data)484 void ContextHub::onDebugDumpData(const ::chre::fbs::DebugDumpDataT &data) {
485   auto str = std::string(reinterpret_cast<const char *>(data.debug_str.data()),
486                          data.debug_str.size());
487   debugDumpAppend(str);
488 }
489 
onDebugDumpComplete(const::chre::fbs::DebugDumpResponseT &)490 void ContextHub::onDebugDumpComplete(
491     const ::chre::fbs::DebugDumpResponseT & /* response */) {
492   debugDumpComplete();
493 }
494 
onContextHubV4Message(const::chre::fbs::ChreMessageUnion & message)495 bool ContextHub::onContextHubV4Message(
496     const ::chre::fbs::ChreMessageUnion &message) {
497   if (mV4Impl) return mV4Impl->handleMessageFromChre(message);
498   return false;
499 }
500 
handleServiceDeath()501 void ContextHub::handleServiceDeath() {
502   LOGI("Context Hub Service died ...");
503   {
504     std::lock_guard<std::mutex> lock(mCallbackMutex);
505     mCallback.reset();
506   }
507   {
508     std::lock_guard<std::mutex> lock(mConnectedHostEndpointsMutex);
509     mConnectedHostEndpoints.clear();
510   }
511 }
512 
onServiceDied(void * cookie)513 void ContextHub::onServiceDied(void *cookie) {
514   auto *contexthub = static_cast<ContextHub *>(cookie);
515   contexthub->handleServiceDeath();
516 }
517 
dump(int fd,const char **,uint32_t)518 binder_status_t ContextHub::dump(int fd, const char ** /* args */,
519                                  uint32_t /* numArgs */) {
520   debugDumpStart(fd);
521   debugDumpFinish();
522   return STATUS_OK;
523 }
524 
debugDumpFinish()525 void ContextHub::debugDumpFinish() {
526   if (checkDebugFd()) {
527     const std::string &dump = mEventLogger.dump();
528     writeToDebugFile(dump.c_str());
529     writeToDebugFile("\n-- End of CHRE/ASH debug info --\n");
530     invalidateDebugFd();
531   }
532 }
533 
writeToDebugFile(const char * str)534 void ContextHub::writeToDebugFile(const char *str) {
535   if (!::android::base::WriteStringToFd(std::string(str), getDebugFd())) {
536     LOGW("Failed to write %zu bytes to debug dump fd", strlen(str));
537   }
538 }
539 
enableTestMode()540 ScopedAStatus ContextHub::enableTestMode() {
541   std::unique_lock<std::mutex> lock(mTestModeMutex);
542 
543   bool success = false;
544   std::vector<int64_t> loadedNanoappIds;
545   std::vector<int64_t> preloadedNanoappIds;
546   std::vector<int64_t> nanoappIdsToUnload;
547   if (mIsTestModeEnabled) {
548     success = true;
549   } else if (mConnection->isLoadTransactionPending()) {
550     /**
551      * There is already a pending load transaction. We cannot change the test
552      * mode state if there is a pending load transaction. We do not consider
553      * pending unload transactions as they can happen asynchronously and
554      * multiple at a time.
555      */
556     LOGE("There exists a pending load transaction. Cannot enable test mode.");
557   } else if (!queryNanoappsInternal(kDefaultHubId, &loadedNanoappIds)) {
558     LOGE("Could not query nanoapps to enable test mode.");
559   } else if (!getPreloadedNanoappIds(kDefaultHubId, &preloadedNanoappIds)
560                   .isOk()) {
561     LOGE("Unable to get preloaded nanoapp IDs from the config file.");
562   } else {
563     std::sort(loadedNanoappIds.begin(), loadedNanoappIds.end());
564     std::sort(preloadedNanoappIds.begin(), preloadedNanoappIds.end());
565 
566     // Calculate the system nanoapp IDs. They are preloaded, but not loaded.
567     mSystemNanoappIds.clear();
568     std::set_difference(preloadedNanoappIds.begin(), preloadedNanoappIds.end(),
569                         loadedNanoappIds.begin(), loadedNanoappIds.end(),
570                         std::back_inserter(mSystemNanoappIds));
571 
572     /*
573      * Unload all preloaded and loaded nanoapps (set intersection).
574      * Both vectors need to be sorted for std::set_intersection to work.
575      * We explicitly choose not to use std::set here to avoid the
576      * copying cost as well as the tree balancing cost for the
577      * red-black tree.
578      */
579     std::set_intersection(loadedNanoappIds.begin(), loadedNanoappIds.end(),
580                           preloadedNanoappIds.begin(),
581                           preloadedNanoappIds.end(),
582                           std::back_inserter(nanoappIdsToUnload));
583     if (!unloadNanoappsInternal(kDefaultHubId, nanoappIdsToUnload)) {
584       LOGE("Unable to unload all loaded and preloaded nanoapps.");
585     }
586     success = true;
587   }
588 
589   if (success) {
590     mIsTestModeEnabled = true;
591     LOGI("Successfully enabled test mode.");
592     return ScopedAStatus::ok();
593   } else {
594     return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
595   }
596 }
597 
disableTestMode()598 ScopedAStatus ContextHub::disableTestMode() {
599   std::unique_lock<std::mutex> lock(mTestModeMutex);
600 
601   bool success = false;
602   std::vector<chrePreloadedNanoappInfo> preloadedNanoapps;
603   std::string preloadedNanoappDirectory;
604   if (!mIsTestModeEnabled) {
605     success = true;
606   } else if (mConnection->isLoadTransactionPending()) {
607     /**
608      * There is already a pending load transaction. We cannot change the test
609      * mode state if there is a pending load transaction. We do not consider
610      * pending unload transactions as they can happen asynchronously and
611      * multiple at a time.
612      */
613     LOGE("There exists a pending load transaction. Cannot disable test mode.");
614   } else if (!getPreloadedNanoappIdsFromConfigFile(
615                  preloadedNanoapps, &preloadedNanoappDirectory)) {
616     LOGE("Unable to get preloaded nanoapp IDs from the config file.");
617   } else {
618     std::vector<NanoappBinary> nanoappsToLoad = selectPreloadedNanoappsToLoad(
619         preloadedNanoapps, preloadedNanoappDirectory);
620 
621     if (!loadNanoappsInternal(kDefaultHubId, nanoappsToLoad)) {
622       LOGE("Unable to load all preloaded, non-system nanoapps.");
623     }
624     // Any attempt to load non-test nanoapps should disable test mode, even if
625     // not all nanoapps are successfully loaded.
626     success = true;
627   }
628 
629   if (success) {
630     mIsTestModeEnabled = false;
631     LOGI("Successfully disabled test mode.");
632     return ScopedAStatus::ok();
633   } else {
634     return ScopedAStatus::fromExceptionCode(EX_SERVICE_SPECIFIC);
635   }
636 }
637 
queryNanoappsInternal(int32_t contextHubId,std::vector<int64_t> * nanoappIdList)638 bool ContextHub::queryNanoappsInternal(int32_t contextHubId,
639                                        std::vector<int64_t> *nanoappIdList) {
640   if (contextHubId != kDefaultHubId) {
641     LOGE("Invalid ID %" PRId32, contextHubId);
642     return false;
643   }
644 
645   std::unique_lock<std::mutex> lock(mQueryNanoappsInternalMutex);
646   mQueryNanoappsInternalList.reset();
647 
648   bool success =
649       queryNanoapps(contextHubId).isOk() &&
650       mQueryNanoappsInternalCondVar.wait_for(lock, kTestModeTimeout, [this]() {
651         return mQueryNanoappsInternalList.has_value();
652       });
653   if (success && nanoappIdList != nullptr) {
654     std::transform(
655         mQueryNanoappsInternalList->begin(), mQueryNanoappsInternalList->end(),
656         std::back_inserter(*nanoappIdList),
657         [](const NanoappInfo &nanoapp) { return nanoapp.nanoappId; });
658   }
659   return success;
660 }
661 
loadNanoappInternal(const NanoappBinary & appBinary,int32_t transactionId)662 bool ContextHub::loadNanoappInternal(const NanoappBinary &appBinary,
663                                      int32_t transactionId) {
664   uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
665                               (appBinary.targetChreApiMinorVersion << 16);
666   FragmentedLoadTransaction transaction(
667       transactionId, appBinary.nanoappId, appBinary.nanoappVersion,
668       appBinary.flags, targetApiVersion, appBinary.customBinary);
669   bool success = mConnection->loadNanoapp(transaction);
670   mEventLogger.logNanoappLoad(appBinary.nanoappId,
671                               appBinary.customBinary.size(),
672                               appBinary.nanoappVersion, success);
673   return success;
674 }
675 
loadNanoappsInternal(int32_t contextHubId,const std::vector<NanoappBinary> & nanoappBinaryList)676 bool ContextHub::loadNanoappsInternal(
677     int32_t contextHubId, const std::vector<NanoappBinary> &nanoappBinaryList) {
678   if (contextHubId != kDefaultHubId) {
679     LOGE("Invalid ID %" PRId32, contextHubId);
680     return false;
681   }
682 
683   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
684   mSynchronousLoadUnloadTransactionId = kStartingInternalTransactionId;
685 
686   for (const NanoappBinary &nanoappToLoad : nanoappBinaryList) {
687     LOGI("Loading nanoapp with ID: 0x%016" PRIx64, nanoappToLoad.nanoappId);
688 
689     bool success = false;
690     if (!loadNanoappInternal(nanoappToLoad,
691                              *mSynchronousLoadUnloadTransactionId)) {
692       LOGE("Failed to request loading nanoapp with ID 0x%" PRIx64,
693            nanoappToLoad.nanoappId);
694     } else {
695       mSynchronousLoadUnloadSuccess.reset();
696       mSynchronousLoadUnloadCondVar.wait_for(lock, kTestModeTimeout, [this]() {
697         return mSynchronousLoadUnloadSuccess.has_value();
698       });
699       if (mSynchronousLoadUnloadSuccess.has_value() &&
700           *mSynchronousLoadUnloadSuccess) {
701         LOGI("Successfully loaded nanoapp with ID: 0x%016" PRIx64,
702              nanoappToLoad.nanoappId);
703         success = true;
704       }
705     }
706 
707     if (!success) {
708       LOGE("Failed to load nanoapp with ID 0x%" PRIx64,
709            nanoappToLoad.nanoappId);
710     }
711     ++(*mSynchronousLoadUnloadTransactionId);
712   }
713 
714   return true;
715 }
716 
unloadNanoappInternal(int64_t appId,int32_t transactionId)717 bool ContextHub::unloadNanoappInternal(int64_t appId, int32_t transactionId) {
718   bool success = mConnection->unloadNanoapp(appId, transactionId);
719   mEventLogger.logNanoappUnload(appId, success);
720   return success;
721 }
722 
unloadNanoappsInternal(int32_t contextHubId,const std::vector<int64_t> & nanoappIdList)723 bool ContextHub::unloadNanoappsInternal(
724     int32_t contextHubId, const std::vector<int64_t> &nanoappIdList) {
725   if (contextHubId != kDefaultHubId) {
726     LOGE("Invalid ID %" PRId32, contextHubId);
727     return false;
728   }
729 
730   std::unique_lock<std::mutex> lock(mSynchronousLoadUnloadMutex);
731   mSynchronousLoadUnloadTransactionId = kStartingInternalTransactionId;
732 
733   for (int64_t nanoappIdToUnload : nanoappIdList) {
734     LOGI("Unloading nanoapp with ID: 0x%016" PRIx64, nanoappIdToUnload);
735 
736     bool success = false;
737     if (!unloadNanoappInternal(nanoappIdToUnload,
738                                *mSynchronousLoadUnloadTransactionId)) {
739       LOGE("Failed to request unloading nanoapp with ID 0x%" PRIx64,
740            nanoappIdToUnload);
741     } else {
742       mSynchronousLoadUnloadSuccess.reset();
743       mSynchronousLoadUnloadCondVar.wait_for(lock, kTestModeTimeout, [this]() {
744         return mSynchronousLoadUnloadSuccess.has_value();
745       });
746       if (mSynchronousLoadUnloadSuccess.has_value() &&
747           *mSynchronousLoadUnloadSuccess) {
748         LOGI("Successfully unloaded nanoapp with ID: 0x%016" PRIx64,
749              nanoappIdToUnload);
750 
751         success = true;
752       }
753     }
754 
755     if (!success) {
756       LOGE("Failed to unload nanoapp with ID 0x%" PRIx64, nanoappIdToUnload);
757     }
758     ++(*mSynchronousLoadUnloadTransactionId);
759   }
760 
761   return true;
762 }
763 
getPreloadedNanoappIdsFromConfigFile(std::vector<chrePreloadedNanoappInfo> & out_preloadedNanoapps,std::string * out_directory) const764 bool ContextHub::getPreloadedNanoappIdsFromConfigFile(
765     std::vector<chrePreloadedNanoappInfo> &out_preloadedNanoapps,
766     std::string *out_directory) const {
767   std::vector<std::string> nanoappNames;
768   std::string directory;
769 
770   bool success = getPreloadedNanoappsFromConfigFile(
771       kPreloadedNanoappsConfigPath, directory, nanoappNames);
772   if (!success) {
773     LOGE("Failed to parse preloaded nanoapps config file");
774   }
775 
776   for (const std::string &nanoappName : nanoappNames) {
777     std::string headerFile = directory + "/" + nanoappName + ".napp_header";
778     std::vector<uint8_t> headerBuffer;
779     if (!readFileContents(headerFile.c_str(), headerBuffer)) {
780       LOGE("Cannot read header file: %s", headerFile.c_str());
781       continue;
782     }
783 
784     if (headerBuffer.size() != sizeof(NanoAppBinaryHeader)) {
785       LOGE("Header size mismatch");
786       continue;
787     }
788 
789     const auto *appHeader =
790         reinterpret_cast<const NanoAppBinaryHeader *>(headerBuffer.data());
791     out_preloadedNanoapps.emplace_back(static_cast<int64_t>(appHeader->appId),
792                                        nanoappName, *appHeader);
793   }
794 
795   if (out_directory != nullptr) {
796     *out_directory = directory;
797   }
798 
799   return true;
800 }
801 
selectPreloadedNanoappsToLoad(std::vector<chrePreloadedNanoappInfo> & preloadedNanoapps,const std::string & preloadedNanoappDirectory)802 std::vector<NanoappBinary> ContextHub::selectPreloadedNanoappsToLoad(
803     std::vector<chrePreloadedNanoappInfo> &preloadedNanoapps,
804     const std::string &preloadedNanoappDirectory) {
805   std::vector<NanoappBinary> nanoappsToLoad;
806 
807   for (auto &preloadedNanoapp : preloadedNanoapps) {
808     int64_t nanoappId = preloadedNanoapp.id;
809 
810     // A nanoapp is a system nanoapp if it is in the preloaded nanoapp list
811     // but not in the loaded nanoapp list as CHRE hides system nanoapps
812     // from the HAL.
813     bool isSystemNanoapp =
814         std::any_of(mSystemNanoappIds.begin(), mSystemNanoappIds.end(),
815                     [nanoappId](int64_t systemNanoappId) {
816                       return systemNanoappId == nanoappId;
817                     });
818     if (!isSystemNanoapp) {
819       std::vector<uint8_t> nanoappBuffer;
820       std::string nanoappFile =
821           preloadedNanoappDirectory + "/" + preloadedNanoapp.name + ".so";
822       if (!readFileContents(nanoappFile.c_str(), nanoappBuffer)) {
823         LOGE("Cannot read header file: %s", nanoappFile.c_str());
824       } else {
825         NanoappBinary nanoapp;
826         nanoapp.nanoappId = preloadedNanoapp.header.appId;
827         nanoapp.nanoappVersion = preloadedNanoapp.header.appVersion;
828         nanoapp.flags = preloadedNanoapp.header.flags;
829         nanoapp.targetChreApiMajorVersion =
830             preloadedNanoapp.header.targetChreApiMajorVersion;
831         nanoapp.targetChreApiMinorVersion =
832             preloadedNanoapp.header.targetChreApiMinorVersion;
833         nanoapp.customBinary = nanoappBuffer;
834 
835         nanoappsToLoad.push_back(nanoapp);
836       }
837     }
838   }
839   return nanoappsToLoad;
840 }
841 
842 }  // namespace aidl::android::hardware::contexthub
843