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