1 /* 2 * Copyright (C) 2016 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 "Contexthub.h" 18 19 #include <inttypes.h> 20 21 #include <log/log.h> 22 23 #include <android/hardware/contexthub/1.0/IContexthub.h> 24 #include <hardware/context_hub.h> 25 #include <sys/endian.h> 26 27 #undef LOG_TAG 28 #define LOG_TAG "ContextHubHalAdapter" 29 30 namespace android { 31 namespace hardware { 32 namespace contexthub { 33 namespace V1_0 { 34 namespace implementation { 35 36 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF); 37 38 Contexthub::Contexthub() 39 : mInitCheck(NO_INIT), 40 mContextHubModule(nullptr), 41 mDeathRecipient(new DeathRecipient(this)), 42 mIsTransactionPending(false) { 43 const hw_module_t *module; 44 45 mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module); 46 47 if (mInitCheck != OK) { 48 ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck)); 49 } else if (module == nullptr) { 50 ALOGE("hal returned succes but a null module!"); 51 // Assign an error, this should not really happen... 52 mInitCheck = UNKNOWN_ERROR; 53 } else { 54 ALOGI("Loaded Context Hub module"); 55 mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module); 56 } 57 } 58 59 bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) { 60 if (!isValidHubId(hubId)) { 61 ALOGW("%s: Hub information is null for hubHandle %d", 62 __FUNCTION__, 63 hubId); 64 return false; 65 } else { 66 msg->app_name = mCachedHubInfo[hubId].osAppName; 67 return true; 68 } 69 } 70 71 Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) { 72 std::vector<ContextHub> hubs; 73 if (isInitialized()) { 74 const context_hub_t *hubArray = nullptr; 75 size_t numHubs; 76 77 // Explicitly discarding const. HAL method discards it. 78 numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule), 79 &hubArray); 80 ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs); 81 82 mCachedHubInfo.clear(); 83 84 for (size_t i = 0; i < numHubs; i++) { 85 CachedHubInformation info; 86 ContextHub c; 87 88 c.hubId = hubArray[i].hub_id; 89 c.name = hubArray[i].name; 90 c.vendor = hubArray[i].vendor; 91 c.toolchain = hubArray[i].toolchain; 92 c.toolchainVersion = hubArray[i].toolchain_version; 93 c.platformVersion = hubArray[i].platform_version; 94 c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len; 95 c.peakMips = hubArray[i].peak_mips; 96 c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw; 97 c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw; 98 c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw; 99 100 info.callback = nullptr; 101 info.osAppName = hubArray[i].os_app_name; 102 mCachedHubInfo[hubArray[i].hub_id] = info; 103 104 hubs.push_back(c); 105 } 106 } else { 107 ALOGW("Context Hub Hal Adapter not initialized"); 108 } 109 110 _hidl_cb(hubs); 111 return Void(); 112 } 113 114 Contexthub::DeathRecipient::DeathRecipient(sp<Contexthub> contexthub) 115 : mContexthub(contexthub) {} 116 117 void Contexthub::DeathRecipient::serviceDied( 118 uint64_t cookie, 119 const wp<::android::hidl::base::V1_0::IBase>& /*who*/) { 120 uint32_t hubId = static_cast<uint32_t>(cookie); 121 mContexthub->handleServiceDeath(hubId); 122 } 123 124 bool Contexthub::isValidHubId(uint32_t hubId) { 125 if (!mCachedHubInfo.count(hubId)) { 126 ALOGW("Hub information not found for hubId %" PRIu32, hubId); 127 return false; 128 } else { 129 return true; 130 } 131 } 132 133 sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) { 134 if (!isValidHubId(hubId)) { 135 return nullptr; 136 } else { 137 return mCachedHubInfo[hubId].callback; 138 } 139 } 140 141 Return<Result> Contexthub::sendMessageToHub(uint32_t hubId, 142 const ContextHubMsg &msg) { 143 if (!isInitialized()) { 144 return Result::NOT_INIT; 145 } 146 147 if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) { 148 return Result::BAD_PARAMS; 149 } 150 151 hub_message_t txMsg = { 152 .app_name.id = msg.appName, 153 .message_type = msg.msgType, 154 .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above 155 .message = static_cast<const uint8_t *>(msg.msg.data()), 156 }; 157 158 // Use a dummy to prevent send_message with empty message from failing prematurely 159 static uint8_t dummy; 160 if (txMsg.message_len == 0 && txMsg.message == nullptr) { 161 txMsg.message = &dummy; 162 } 163 164 ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64, 165 txMsg.message_type, 166 txMsg.message_len, 167 txMsg.app_name.id); 168 169 if(mContextHubModule->send_message(hubId, &txMsg) != 0) { 170 return Result::TRANSACTION_FAILED; 171 } 172 173 return Result::OK; 174 } 175 176 Return<Result> Contexthub::reboot(uint32_t hubId) { 177 if (!isInitialized()) { 178 return Result::NOT_INIT; 179 } 180 181 hub_message_t msg; 182 183 if (setOsAppAsDestination(&msg, hubId) == false) { 184 return Result::BAD_PARAMS; 185 } 186 187 msg.message_type = CONTEXT_HUB_OS_REBOOT; 188 msg.message_len = 0; 189 msg.message = nullptr; 190 191 if(mContextHubModule->send_message(hubId, &msg) != 0) { 192 return Result::TRANSACTION_FAILED; 193 } else { 194 return Result::OK; 195 } 196 } 197 198 Return<Result> Contexthub::registerCallback(uint32_t hubId, 199 const sp<IContexthubCallback> &cb) { 200 Return<Result> retVal = Result::BAD_PARAMS; 201 202 if (!isInitialized()) { 203 // Not initilalized 204 ALOGW("Context hub not initialized successfully"); 205 retVal = Result::NOT_INIT; 206 } else if (!isValidHubId(hubId)) { 207 // Initialized, but hubId is not valid 208 retVal = Result::BAD_PARAMS; 209 } else if (mContextHubModule->subscribe_messages(hubId, 210 contextHubCb, 211 this) == 0) { 212 // Initialized && valid hub && subscription successful 213 if (mCachedHubInfo[hubId].callback != nullptr) { 214 ALOGD("Modifying callback for hubId %" PRIu32, hubId); 215 mCachedHubInfo[hubId].callback->unlinkToDeath(mDeathRecipient); 216 } 217 218 mCachedHubInfo[hubId].callback = cb; 219 if (cb != nullptr) { 220 Return<bool> linkResult = cb->linkToDeath(mDeathRecipient, hubId); 221 bool linkSuccess = linkResult.isOk() ? 222 static_cast<bool>(linkResult) : false; 223 if (!linkSuccess) { 224 ALOGW("Couldn't link death recipient for hubId %" PRIu32, 225 hubId); 226 } 227 } 228 retVal = Result::OK; 229 } else { 230 // Initalized && valid hubId - but subscription unsuccessful 231 // This is likely an internal error in the HAL implementation, but we 232 // cannot add more information. 233 ALOGW("Could not subscribe to the hub for callback"); 234 retVal = Result::UNKNOWN_FAILURE; 235 } 236 237 return retVal; 238 } 239 240 static bool isValidOsStatus(const uint8_t *msg, 241 size_t msgLen, 242 status_response_t *rsp) { 243 // Workaround a bug in some HALs 244 if (msgLen == 1) { 245 rsp->result = msg[0]; 246 return true; 247 } 248 249 if (msg == nullptr || msgLen != sizeof(*rsp)) { 250 ALOGI("Received invalid response (is null : %d, size %zu)", 251 msg == nullptr ? 1 : 0, 252 msgLen); 253 return false; 254 } 255 256 memcpy(rsp, msg, sizeof(*rsp)); 257 258 // No sanity checks on return values 259 return true; 260 } 261 262 int Contexthub::handleOsMessage(sp<IContexthubCallback> cb, 263 uint32_t msgType, 264 const uint8_t *msg, 265 int msgLen) { 266 int retVal = -1; 267 268 269 switch(msgType) { 270 case CONTEXT_HUB_APPS_ENABLE: 271 case CONTEXT_HUB_APPS_DISABLE: 272 case CONTEXT_HUB_LOAD_APP: 273 case CONTEXT_HUB_UNLOAD_APP: 274 { 275 struct status_response_t rsp; 276 TransactionResult result; 277 if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) { 278 retVal = 0; 279 result = TransactionResult::SUCCESS; 280 } else { 281 result = TransactionResult::FAILURE; 282 } 283 284 mIsTransactionPending = false; 285 if (cb != nullptr) { 286 cb->handleTxnResult(mTransactionId, result); 287 } 288 retVal = 0; 289 break; 290 } 291 292 case CONTEXT_HUB_QUERY_APPS: 293 { 294 std::vector<HubAppInfo> apps; 295 int numApps = msgLen / sizeof(hub_app_info); 296 const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg); 297 298 for (int i = 0; i < numApps; i++) { 299 hub_app_info query_info; 300 memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info)); 301 HubAppInfo app; 302 app.appId = query_info.app_name.id; 303 app.version = query_info.version; 304 // TODO :: Add memory ranges 305 306 apps.push_back(app); 307 } 308 309 if (cb != nullptr) { 310 cb->handleAppsInfo(apps); 311 } 312 retVal = 0; 313 break; 314 } 315 316 case CONTEXT_HUB_QUERY_MEMORY: 317 { 318 // Deferring this use 319 retVal = 0; 320 break; 321 } 322 323 case CONTEXT_HUB_OS_REBOOT: 324 { 325 mIsTransactionPending = false; 326 if (cb != nullptr) { 327 cb->handleHubEvent(AsyncEventType::RESTARTED); 328 } 329 retVal = 0; 330 break; 331 } 332 333 default: 334 { 335 retVal = -1; 336 break; 337 } 338 } 339 340 return retVal; 341 } 342 343 void Contexthub::handleServiceDeath(uint32_t hubId) { 344 ALOGI("Callback/service died for hubId %" PRIu32, hubId); 345 int ret = mContextHubModule->subscribe_messages(hubId, nullptr, nullptr); 346 if (ret != 0) { 347 ALOGW("Failed to unregister callback from hubId %" PRIu32 ": %d", 348 hubId, ret); 349 } 350 mCachedHubInfo[hubId].callback.clear(); 351 } 352 353 int Contexthub::contextHubCb(uint32_t hubId, 354 const struct hub_message_t *rxMsg, 355 void *cookie) { 356 Contexthub *obj = static_cast<Contexthub *>(cookie); 357 358 if (rxMsg == nullptr) { 359 ALOGW("Ignoring NULL message"); 360 return -1; 361 } 362 363 if (!obj->isValidHubId(hubId)) { 364 ALOGW("Invalid hub Id %" PRIu32, hubId); 365 return -1; 366 } 367 368 sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId); 369 370 if (cb == nullptr) { 371 // This should not ever happen 372 ALOGW("No callback registered, returning"); 373 return -1; 374 } 375 376 if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) { 377 obj->handleOsMessage(cb, 378 rxMsg->message_type, 379 static_cast<const uint8_t *>(rxMsg->message), 380 rxMsg->message_len); 381 } else { 382 ContextHubMsg msg; 383 384 msg.appName = rxMsg->app_name.id; 385 msg.msgType = rxMsg->message_type; 386 msg.hostEndPoint = static_cast<uint16_t>(HostEndPoint::BROADCAST); 387 msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message), 388 static_cast<const uint8_t *>(rxMsg->message) + 389 rxMsg->message_len); 390 391 cb->handleClientMsg(msg); 392 } 393 394 return 0; 395 } 396 397 Return<Result> Contexthub::unloadNanoApp(uint32_t hubId, 398 uint64_t appId, 399 uint32_t transactionId) { 400 if (!isInitialized()) { 401 return Result::NOT_INIT; 402 } 403 404 if (mIsTransactionPending) { 405 return Result::TRANSACTION_PENDING; 406 } 407 408 hub_message_t msg; 409 410 if (setOsAppAsDestination(&msg, hubId) == false) { 411 return Result::BAD_PARAMS; 412 } 413 414 struct apps_disable_request_t req; 415 416 msg.message_type = CONTEXT_HUB_UNLOAD_APP; 417 msg.message_len = sizeof(req); 418 msg.message = &req; 419 req.app_name.id = appId; 420 421 if(mContextHubModule->send_message(hubId, &msg) != 0) { 422 return Result::TRANSACTION_FAILED; 423 } else { 424 mTransactionId = transactionId; 425 mIsTransactionPending = true; 426 return Result::OK; 427 } 428 } 429 430 Return<Result> Contexthub::loadNanoApp(uint32_t hubId, 431 const NanoAppBinary& appBinary, 432 uint32_t transactionId) { 433 if (!isInitialized()) { 434 return Result::NOT_INIT; 435 } 436 437 if (mIsTransactionPending) { 438 return Result::TRANSACTION_PENDING; 439 } 440 441 hub_message_t hubMsg; 442 443 if (setOsAppAsDestination(&hubMsg, hubId) == false) { 444 return Result::BAD_PARAMS; 445 } 446 447 // Data from the nanoapp header is passed through HIDL as explicit fields, 448 // but the legacy HAL expects it prepended to the binary, therefore we must 449 // reconstruct it here prior to passing to the legacy HAL. 450 const struct nano_app_binary_t header = { 451 .header_version = htole32(1), 452 .magic = htole32(NANOAPP_MAGIC), 453 .app_id.id = htole64(appBinary.appId), 454 .app_version = htole32(appBinary.appVersion), 455 .flags = htole32(appBinary.flags), 456 .hw_hub_type = htole64(0), 457 .target_chre_api_major_version = appBinary.targetChreApiMajorVersion, 458 .target_chre_api_minor_version = appBinary.targetChreApiMinorVersion, 459 }; 460 const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header); 461 462 std::vector<uint8_t> binaryWithHeader(appBinary.customBinary); 463 binaryWithHeader.insert(binaryWithHeader.begin(), 464 headerBytes, 465 headerBytes + sizeof(header)); 466 467 hubMsg.message_type = CONTEXT_HUB_LOAD_APP; 468 hubMsg.message_len = binaryWithHeader.size(); 469 hubMsg.message = binaryWithHeader.data(); 470 471 if (mContextHubModule->send_message(hubId, &hubMsg) != 0) { 472 return Result::TRANSACTION_FAILED; 473 } else { 474 mTransactionId = transactionId; 475 mIsTransactionPending = true; 476 return Result::OK; 477 } 478 } 479 480 Return<Result> Contexthub::enableNanoApp(uint32_t hubId, 481 uint64_t appId, 482 uint32_t transactionId) { 483 if (!isInitialized()) { 484 return Result::NOT_INIT; 485 } 486 487 if (mIsTransactionPending) { 488 return Result::TRANSACTION_PENDING; 489 } 490 491 hub_message_t msg; 492 493 if (setOsAppAsDestination(&msg, hubId) == false) { 494 return Result::BAD_PARAMS; 495 } 496 497 struct apps_enable_request_t req; 498 499 msg.message_type = CONTEXT_HUB_APPS_ENABLE; 500 msg.message_len = sizeof(req); 501 req.app_name.id = appId; 502 msg.message = &req; 503 504 if(mContextHubModule->send_message(hubId, &msg) != 0) { 505 return Result::TRANSACTION_FAILED; 506 } else { 507 mTransactionId = transactionId; 508 mIsTransactionPending = true; 509 return Result::OK; 510 } 511 } 512 513 Return<Result> Contexthub::disableNanoApp(uint32_t hubId, 514 uint64_t appId, 515 uint32_t transactionId) { 516 if (!isInitialized()) { 517 return Result::NOT_INIT; 518 } 519 520 if (mIsTransactionPending) { 521 return Result::TRANSACTION_PENDING; 522 } 523 524 hub_message_t msg; 525 526 if (setOsAppAsDestination(&msg, hubId) == false) { 527 return Result::BAD_PARAMS; 528 } 529 530 struct apps_disable_request_t req; 531 532 msg.message_type = CONTEXT_HUB_APPS_DISABLE; 533 msg.message_len = sizeof(req); 534 req.app_name.id = appId; 535 msg.message = &req; 536 537 if(mContextHubModule->send_message(hubId, &msg) != 0) { 538 return Result::TRANSACTION_FAILED; 539 } else { 540 mTransactionId = transactionId; 541 mIsTransactionPending = true; 542 return Result::OK; 543 } 544 } 545 546 Return<Result> Contexthub::queryApps(uint32_t hubId) { 547 if (!isInitialized()) { 548 return Result::NOT_INIT; 549 } 550 551 hub_message_t msg; 552 553 if (setOsAppAsDestination(&msg, hubId) == false) { 554 ALOGW("Could not find hubId %" PRIu32, hubId); 555 return Result::BAD_PARAMS; 556 } 557 558 query_apps_request_t payload; 559 payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter 560 msg.message = &payload; 561 msg.message_len = sizeof(payload); 562 msg.message_type = CONTEXT_HUB_QUERY_APPS; 563 564 if(mContextHubModule->send_message(hubId, &msg) != 0) { 565 ALOGW("Query Apps sendMessage failed"); 566 return Result::TRANSACTION_FAILED; 567 } 568 569 return Result::OK; 570 } 571 572 bool Contexthub::isInitialized() { 573 return (mInitCheck == OK && mContextHubModule != nullptr); 574 } 575 576 IContexthub *HIDL_FETCH_IContexthub(const char * halName) { 577 ALOGI("%s Called for %s", __FUNCTION__, halName); 578 Contexthub *contexthub = new Contexthub; 579 580 if (!contexthub->isInitialized()) { 581 delete contexthub; 582 contexthub = nullptr; 583 } 584 585 return contexthub; 586 } 587 588 } // namespace implementation 589 } // namespace V1_0 590 } // namespace contexthub 591 } // namespace hardware 592 } // namespace android 593