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#define LOG_TAG "NanohubHAL" 18 19#include <cassert> 20#include <cerrno> 21#include <cinttypes> 22 23#include <endian.h> 24 25#include <vector> 26 27#include <utils/Log.h> 28 29#include <endian.h> 30 31#include <hardware/context_hub.h> 32#include "nanohub_perdevice.h" 33#include "system_comms.h" 34#include "nanohubhal.h" 35 36namespace android { 37 38namespace nanohub { 39 40static void readAppName(MessageBuf &buf, hub_app_name_t &name) 41{ 42 name.id = buf.readU64(); 43} 44 45static void writeAppName(MessageBuf &buf, const hub_app_name_t &name) 46{ 47 buf.writeU64(name.id); 48} 49 50static void readNanohubAppInfo(MessageBuf &buf, NanohubAppInfo &info) 51{ 52 size_t pos = buf.getPos(); 53 readAppName(buf, info.name); 54 info.version = buf.readU32(); 55 info.flashUse = buf.readU32(); 56 info.ramUse = buf.readU32(); 57 if ((buf.getPos() - pos) != sizeof(info)) { 58 ALOGE("%s: failed to read object", __func__); 59 } 60} 61 62static void readNanohubMemInfo(MessageBuf &buf, NanohubMemInfo &mi) 63{ 64 size_t pos = buf.getPos(); 65 mi.flashSz = buf.readU32(); 66 mi.blSz = buf.readU32(); 67 mi.osSz = buf.readU32(); 68 mi.sharedSz = buf.readU32(); 69 mi.eeSz = buf.readU32(); 70 mi.ramSz = buf.readU32(); 71 72 mi.blUse = buf.readU32(); 73 mi.osUse = buf.readU32(); 74 mi.sharedUse = buf.readU32(); 75 mi.eeUse = buf.readU32(); 76 mi.ramUse = buf.readU32(); 77 if ((buf.getPos() - pos) != sizeof(mi)) { 78 ALOGE("%s: failed to read object", __func__); 79 } 80} 81 82NanohubRsp::NanohubRsp(MessageBuf &buf, bool no_status) 83{ 84 // all responses start with command 85 // most of them have 4-byte status (result code) 86 buf.reset(); 87 cmd = buf.readU8(); 88 if (!buf.getSize()) { 89 status = -EINVAL; 90 } else if (no_status) { 91 status = 0; 92 } else { 93 status = buf.readU32(); 94 } 95} 96 97int SystemComm::sendToSystem(const void *data, size_t len) 98{ 99 if (NanoHub::messageTracingEnabled()) { 100 dumpBuffer("HAL -> SYS", getSystem()->mHostIfAppName, 0, data, len); 101 } 102 return NanoHub::sendToDevice(&getSystem()->mHostIfAppName, data, len); 103} 104 105int SystemComm::AppInfoSession::setup(const hub_message_t *) 106{ 107 std::lock_guard<std::mutex> _l(mLock); 108 int suggestedSize = mAppInfo.size() ? mAppInfo.size() : 20; 109 110 mAppInfo.clear(); 111 mAppInfo.reserve(suggestedSize); 112 setState(SESSION_USER); 113 114 return requestNext(); 115} 116 117inline hub_app_name_t deviceAppNameToHost(const hub_app_name_t src) 118{ 119 hub_app_name_t res = { .id = le64toh(src.id) }; 120 return res; 121} 122 123inline hub_app_name_t hostAppNameToDevice(const hub_app_name_t src) 124{ 125 hub_app_name_t res = { .id = htole64(src.id) }; 126 return res; 127} 128 129int SystemComm::AppInfoSession::handleRx(MessageBuf &buf) 130{ 131 std::lock_guard<std::mutex> _l(mLock); 132 133 NanohubRsp rsp(buf, true); 134 if (rsp.cmd != NANOHUB_QUERY_APPS) { 135 return 1; 136 } 137 size_t len = buf.getRoom(); 138 if (len != sizeof(NanohubAppInfo) && len) { 139 ALOGE("%s: Invalid data size; have %zu, need %zu", __func__, 140 len, sizeof(NanohubAppInfo)); 141 return -EINVAL; 142 } 143 if (getState() != SESSION_USER) { 144 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER); 145 return -EINVAL; 146 } 147 if (len) { 148 NanohubAppInfo info; 149 readNanohubAppInfo(buf, info); 150 hub_app_info appInfo; 151 appInfo.num_mem_ranges = 0; 152 if (info.flashUse != NANOHUB_MEM_SZ_UNKNOWN) { 153 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++]; 154 range.type = HUB_MEM_TYPE_MAIN; 155 range.total_bytes = info.flashUse; 156 } 157 if (info.ramUse != NANOHUB_MEM_SZ_UNKNOWN) { 158 mem_range_t &range = appInfo.mem_usage[appInfo.num_mem_ranges++]; 159 range.type = HUB_MEM_TYPE_RAM; 160 range.total_bytes = info.ramUse; 161 } 162 163 appInfo.app_name = info.name; 164 appInfo.version = info.version; 165 166 mAppInfo.push_back(appInfo); 167 return requestNext(); 168 } else { 169 sendToApp(CONTEXT_HUB_QUERY_APPS, 170 static_cast<const void *>(mAppInfo.data()), 171 mAppInfo.size() * sizeof(mAppInfo[0])); 172 complete(); 173 } 174 175 return 0; 176} 177 178int SystemComm::AppInfoSession::requestNext() 179{ 180 char data[MAX_RX_PACKET]; 181 MessageBuf buf(data, sizeof(data)); 182 buf.writeU8(NANOHUB_QUERY_APPS); 183 buf.writeU32(mAppInfo.size()); 184 return sendToSystem(buf.getData(), buf.getPos()); 185} 186 187int SystemComm::MemInfoSession::setup(const hub_message_t *) 188{ 189 std::lock_guard<std::mutex> _l(mLock); 190 char data[MAX_RX_PACKET]; 191 MessageBuf buf(data, sizeof(data)); 192 buf.writeU8(NANOHUB_QUERY_MEMINFO); 193 194 setState(SESSION_USER); 195 return sendToSystem(buf.getData(), buf.getPos()); 196} 197 198int SystemComm::MemInfoSession::handleRx(MessageBuf &buf) 199{ 200 std::lock_guard<std::mutex> _l(mLock); 201 NanohubRsp rsp(buf, true); 202 203 if (rsp.cmd != NANOHUB_QUERY_MEMINFO) 204 return 1; 205 206 size_t len = buf.getRoom(); 207 208 if (len != sizeof(NanohubMemInfo)) { 209 ALOGE("%s: Invalid data size: %zu", __func__, len); 210 return -EINVAL; 211 } 212 if (getState() != SESSION_USER) { 213 ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER); 214 return -EINVAL; 215 } 216 217 NanohubMemInfo mi; 218 readNanohubMemInfo(buf, mi); 219 std::vector<mem_range_t> ranges; 220 ranges.reserve(4); 221 222 //if each is valid, copy to output area 223 if (mi.sharedSz != NANOHUB_MEM_SZ_UNKNOWN && 224 mi.sharedUse != NANOHUB_MEM_SZ_UNKNOWN) 225 ranges.push_back({ 226 .type = HUB_MEM_TYPE_MAIN, 227 .total_bytes = mi.sharedSz, 228 .free_bytes = mi.sharedSz - mi.sharedUse, 229 }); 230 231 if (mi.osSz != NANOHUB_MEM_SZ_UNKNOWN && 232 mi.osUse != NANOHUB_MEM_SZ_UNKNOWN) 233 ranges.push_back({ 234 .type = HUB_MEM_TYPE_OS, 235 .total_bytes = mi.osSz, 236 .free_bytes = mi.osSz - mi.osUse, 237 }); 238 239 if (mi.eeSz != NANOHUB_MEM_SZ_UNKNOWN && 240 mi.eeUse != NANOHUB_MEM_SZ_UNKNOWN) 241 ranges.push_back({ 242 .type = HUB_MEM_TYPE_EEDATA, 243 .total_bytes = mi.eeSz, 244 .free_bytes = mi.eeSz - mi.eeUse, 245 }); 246 247 if (mi.ramSz != NANOHUB_MEM_SZ_UNKNOWN && 248 mi.ramUse != NANOHUB_MEM_SZ_UNKNOWN) 249 ranges.push_back({ 250 .type = HUB_MEM_TYPE_RAM, 251 .total_bytes = mi.ramSz, 252 .free_bytes = mi.ramSz - mi.ramUse, 253 }); 254 255 //send it out 256 sendToApp(CONTEXT_HUB_QUERY_MEMORY, 257 static_cast<const void *>(ranges.data()), 258 ranges.size() * sizeof(ranges[0])); 259 260 complete(); 261 262 return 0; 263} 264 265int SystemComm::AppMgmtSession::setup(const hub_message_t *appMsg) 266{ 267 std::lock_guard<std::mutex> _l(mLock); 268 269 char data[MAX_RX_PACKET]; 270 MessageBuf buf(data, sizeof(data)); 271 const uint8_t *msgData = static_cast<const uint8_t*>(appMsg->message); 272 273 mCmd = appMsg->message_type; 274 mLen = appMsg->message_len; 275 mPos = 0; 276 277 switch (mCmd) { 278 case CONTEXT_HUB_APPS_ENABLE: 279 return setupMgmt(appMsg, NANOHUB_EXT_APPS_ON); 280 case CONTEXT_HUB_APPS_DISABLE: 281 return setupMgmt(appMsg, NANOHUB_EXT_APPS_OFF); 282 case CONTEXT_HUB_UNLOAD_APP: 283 return setupMgmt(appMsg, NANOHUB_EXT_APP_DELETE); 284 case CONTEXT_HUB_LOAD_APP: 285 { 286 mData.clear(); 287 mData = std::vector<uint8_t>(msgData, msgData + mLen); 288 const load_app_request_t *appReq = static_cast<const load_app_request_t*>(appMsg->message); 289 if (appReq == nullptr || mLen <= sizeof(*appReq)) { 290 ALOGE("%s: Invalid app header: too short\n", __func__); 291 return -EINVAL; 292 } 293 mAppName = appReq->app_binary.app_id; 294 setState(TRANSFER); 295 296 buf.writeU8(NANOHUB_START_UPLOAD); 297 buf.writeU8(0); 298 buf.writeU32(mLen); 299 return sendToSystem(buf.getData(), buf.getPos()); 300 } 301 302 case CONTEXT_HUB_OS_REBOOT: 303 setState(REBOOT); 304 buf.writeU8(NANOHUB_REBOOT); 305 return sendToSystem(buf.getData(), buf.getPos()); 306 } 307 308 return -EINVAL; 309} 310 311int SystemComm::AppMgmtSession::setupMgmt(const hub_message_t *appMsg, uint32_t cmd) 312{ 313 const hub_app_name_t &appName = *static_cast<const hub_app_name_t*>(appMsg->message); 314 if (appMsg->message_len != sizeof(appName)) { 315 return -EINVAL; 316 } 317 318 char data[MAX_RX_PACKET]; 319 MessageBuf buf(data, sizeof(data)); 320 buf.writeU8(cmd); 321 writeAppName(buf, appName); 322 setState(MGMT); 323 324 return sendToSystem(buf.getData(), buf.getPos()); 325} 326 327int SystemComm::AppMgmtSession::handleRx(MessageBuf &buf) 328{ 329 int ret = 0; 330 std::lock_guard<std::mutex> _l(mLock); 331 NanohubRsp rsp(buf); 332 333 switch (getState()) { 334 case TRANSFER: 335 ret = handleTransfer(rsp); 336 break; 337 case FINISH: 338 ret = handleFinish(rsp); 339 break; 340 case RUN: 341 ret = handleRun(rsp); 342 break; 343 case RUN_FAILED: 344 ret = handleRunFailed(rsp); 345 break; 346 case REBOOT: 347 ret = handleReboot(rsp); 348 break; 349 case MGMT: 350 ret = handleMgmt(rsp); 351 break; 352 } 353 354 return ret; 355} 356 357int SystemComm::AppMgmtSession::handleTransfer(NanohubRsp &rsp) 358{ 359 if (rsp.cmd != NANOHUB_CONT_UPLOAD && rsp.cmd != NANOHUB_START_UPLOAD) 360 return 1; 361 362 char data[MAX_RX_PACKET]; 363 MessageBuf buf(data, sizeof(data)); 364 365 static_assert(NANOHUB_UPLOAD_CHUNK_SZ_MAX <= (MAX_RX_PACKET-5), 366 "Invalid chunk size"); 367 368 if (mPos < mLen) { 369 uint32_t chunkSize = mLen - mPos; 370 371 if (chunkSize > NANOHUB_UPLOAD_CHUNK_SZ_MAX) { 372 chunkSize = NANOHUB_UPLOAD_CHUNK_SZ_MAX; 373 } 374 375 buf.writeU8(NANOHUB_CONT_UPLOAD); 376 buf.writeU32(mPos); 377 buf.writeRaw(&mData[mPos], chunkSize); 378 mPos += chunkSize; 379 } else { 380 buf.writeU8(NANOHUB_FINISH_UPLOAD); 381 setState(FINISH); 382 } 383 384 return sendToSystem(buf.getData(), buf.getPos()); 385} 386 387int SystemComm::AppMgmtSession::handleFinish(NanohubRsp &rsp) 388{ 389 if (rsp.cmd != NANOHUB_FINISH_UPLOAD) 390 return 1; 391 392 int ret = 0; 393 const bool success = rsp.status != 0; 394 mData.clear(); 395 396 if (success) { 397 char data[MAX_RX_PACKET]; 398 MessageBuf buf(data, sizeof(data)); 399 buf.writeU8(NANOHUB_EXT_APPS_ON); 400 writeAppName(buf, mAppName); 401 setState(RUN); 402 ret = sendToSystem(buf.getData(), buf.getPos()); 403 } else { 404 int32_t result = NANOHUB_APP_NOT_LOADED; 405 406 sendToApp(mCmd, &result, sizeof(result)); 407 complete(); 408 } 409 410 return ret; 411} 412 413int SystemComm::AppMgmtSession::handleRun(NanohubRsp &rsp) 414{ 415 if (rsp.cmd != NANOHUB_EXT_APPS_ON) 416 return 1; 417 418 MgmtStatus sts = { .value = (uint32_t)rsp.status }; 419 420 // op counter returns number of nanoapps that were started as result of the command 421 // for successful start command it must be > 0 422 int32_t result = sts.value > 0 && sts.op > 0 && sts.op <= 0x7F ? 0 : -1; 423 424 ALOGI("Nanohub NEW APP START: %08" PRIX32 "\n", rsp.status); 425 if (result != 0) { 426 // if nanoapp failed to start we have to unload it 427 char data[MAX_RX_PACKET]; 428 MessageBuf buf(data, sizeof(data)); 429 buf.writeU8(NANOHUB_EXT_APP_DELETE); 430 writeAppName(buf, mAppName); 431 if (sendToSystem(buf.getData(), buf.getPos()) == 0) { 432 setState(RUN_FAILED); 433 return 0; 434 } 435 ALOGE("%s: failed to send DELETE for failed app\n", __func__); 436 } 437 438 // it is either success, and we report it, or 439 // it is a failure to load, and also failure to send erase command 440 sendToApp(mCmd, &result, sizeof(result)); 441 complete(); 442 return 0; 443} 444 445int SystemComm::AppMgmtSession::handleRunFailed(NanohubRsp &rsp) 446{ 447 if (rsp.cmd != NANOHUB_EXT_APP_DELETE) 448 return 1; 449 450 int32_t result = -1; 451 452 ALOGI("%s: APP DELETE [because it failed]: %08" PRIX32 "\n", __func__, rsp.status); 453 454 sendToApp(mCmd, &result, sizeof(result)); 455 complete(); 456 457 return 0; 458} 459 460/* reboot notification, when triggered by App request */ 461int SystemComm::AppMgmtSession::handleReboot(NanohubRsp &rsp) 462{ 463 if (rsp.cmd != NANOHUB_REBOOT) 464 return 1; 465 ALOGI("Nanohub reboot status [USER REQ]: %08" PRIX32 "\n", rsp.status); 466 467 // reboot notification is sent by SessionManager 468 complete(); 469 470 return 0; 471} 472 473int SystemComm::AppMgmtSession::handleMgmt(NanohubRsp &rsp) 474{ 475 bool valid = false; 476 477 int32_t result = rsp.status; 478 479 // TODO: remove this when context hub service can handle non-zero success status 480 if (result > 0) { 481 // something happened; assume it worked 482 result = 0; 483 } else if (result == 0) { 484 // nothing happened; this is provably an error 485 result = -1; 486 } 487 488 switch (rsp.cmd) { 489 case NANOHUB_EXT_APPS_OFF: 490 valid = mCmd == CONTEXT_HUB_APPS_DISABLE; 491 break; 492 case NANOHUB_EXT_APPS_ON: 493 valid = mCmd == CONTEXT_HUB_APPS_ENABLE; 494 break; 495 case NANOHUB_EXT_APP_DELETE: 496 valid = mCmd == CONTEXT_HUB_UNLOAD_APP; 497 break; 498 default: 499 return 1; 500 } 501 502 ALOGI("Nanohub MGMT response: CMD=%02X; STATUS=%08" PRIX32, rsp.cmd, rsp.status); 503 if (!valid) { 504 ALOGE("Invalid response for this state: APP CMD=%02X", mCmd); 505 return -EINVAL; 506 } 507 508 sendToApp(mCmd, &result, sizeof(result)); 509 complete(); 510 511 return 0; 512} 513 514int SystemComm::KeyInfoSession::setup(const hub_message_t *) { 515 std::lock_guard<std::mutex> _l(mLock); 516 mRsaKeyData.clear(); 517 setState(SESSION_USER); 518 mStatus = -EBUSY; 519 return requestRsaKeys(); 520} 521 522int SystemComm::KeyInfoSession::handleRx(MessageBuf &buf) 523{ 524 std::lock_guard<std::mutex> _l(mLock); 525 NanohubRsp rsp(buf, true); 526 527 if (getState() != SESSION_USER) { 528 // invalid state 529 mStatus = -EFAULT; 530 return mStatus; 531 } 532 533 if (buf.getRoom()) { 534 mRsaKeyData.insert(mRsaKeyData.end(), 535 buf.getData() + buf.getPos(), 536 buf.getData() + buf.getSize()); 537 return requestRsaKeys(); 538 } else { 539 mStatus = 0; 540 complete(); 541 return 0; 542 } 543} 544 545int SystemComm::KeyInfoSession::requestRsaKeys(void) 546{ 547 char data[MAX_RX_PACKET]; 548 MessageBuf buf(data, sizeof(data)); 549 550 buf.writeU8(NANOHUB_QUERY_APPS); 551 buf.writeU32(mRsaKeyData.size()); 552 553 return sendToSystem(buf.getData(), buf.getPos()); 554} 555 556int SystemComm::doHandleRx(const nano_message *msg) 557{ 558 //we only care for messages from HostIF 559 if (msg->hdr.appId != mHostIfAppName.id) 560 return 1; 561 562 //they must all be at least 1 byte long 563 if (!msg->hdr.len) { 564 return -EINVAL; 565 } 566 MessageBuf buf(reinterpret_cast<const char*>(msg->data), msg->hdr.len); 567 if (NanoHub::messageTracingEnabled()) { 568 dumpBuffer("SYS -> HAL", mHostIfAppName, 0, buf.getData(), buf.getSize()); 569 } 570 int status = mSessions.handleRx(buf); 571 if (status) { 572 // provide default handler for any system message, that is not properly handled 573 dumpBuffer(status > 0 ? "HAL (not handled)" : "HAL (error)", 574 mHostIfAppName, 0, buf.getData(), buf.getSize(), status); 575 status = status > 0 ? 0 : status; 576 } 577 578 return status; 579} 580 581int SystemComm::SessionManager::handleRx(MessageBuf &buf) 582{ 583 int status = 1; 584 std::unique_lock<std::mutex> lk(lock); 585 586 // pass message to all active sessions, in arbitrary order 587 // 1st session that handles the message terminates the loop 588 for (auto pos = sessions_.begin(); pos != sessions_.end() && status > 0; next(pos)) { 589 if (!isActive(pos)) { 590 continue; 591 } 592 Session *session = pos->second; 593 status = session->handleRx(buf); 594 if (status < 0) { 595 session->complete(); 596 } 597 } 598 599 NanohubRsp rsp(buf); 600 if (rsp.cmd == NANOHUB_REBOOT) { 601 // if this is reboot notification, kill all sessions 602 for (auto pos = sessions_.begin(); pos != sessions_.end(); next(pos)) { 603 if (!isActive(pos)) { 604 continue; 605 } 606 Session *session = pos->second; 607 session->abort(-EINTR); 608 } 609 lk.unlock(); 610 // log the reboot event, if not handled 611 if (status > 0) { 612 ALOGW("Nanohub reboot status [UNSOLICITED]: %08" PRIX32, rsp.status); 613 status = 0; 614 } 615 // report to java apps 616 sendToApp(CONTEXT_HUB_OS_REBOOT, &rsp.status, sizeof(rsp.status)); 617 } 618 619 return status; 620} 621 622int SystemComm::SessionManager::setup_and_add(int id, Session *session, const hub_message_t *appMsg) 623{ 624 std::lock_guard<std::mutex> _l(lock); 625 626 // scan sessions to release those that are already done 627 for (auto pos = sessions_.begin(); pos != sessions_.end(); next(pos)) { 628 continue; 629 } 630 631 if (sessions_.count(id) == 0 && !session->isRunning()) { 632 sessions_[id] = session; 633 int ret = session->setup(appMsg); 634 if (ret < 0) { 635 session->complete(); 636 } 637 return ret; 638 } 639 return -EBUSY; 640} 641 642int SystemComm::doHandleTx(const hub_message_t *appMsg) 643{ 644 int status = 0; 645 646 switch (appMsg->message_type) { 647 case CONTEXT_HUB_LOAD_APP: 648 if (!mKeySession.haveKeys()) { 649 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mKeySession, appMsg); 650 if (status < 0) { 651 break; 652 } 653 mKeySession.wait(); 654 status = mKeySession.getStatus(); 655 if (status < 0) { 656 break; 657 } 658 } 659 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg); 660 break; 661 case CONTEXT_HUB_APPS_ENABLE: 662 case CONTEXT_HUB_APPS_DISABLE: 663 case CONTEXT_HUB_UNLOAD_APP: 664 // all APP-modifying commands share session key, to ensure they can't happen at the same time 665 status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg); 666 break; 667 668 case CONTEXT_HUB_QUERY_APPS: 669 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_APPS, &mAppInfoSession, appMsg); 670 break; 671 672 case CONTEXT_HUB_QUERY_MEMORY: 673 status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_MEMORY, &mMemInfoSession, appMsg); 674 break; 675 676 default: 677 ALOGW("Unknown os message type %u\n", appMsg->message_type); 678 return -EINVAL; 679 } 680 681 return status; 682} 683 684}; // namespace nanohub 685 686}; // namespace android 687