diff options
author | Tianjie Xu | 2017-11-28 19:23:06 -0600 |
---|---|---|
committer | Tianjie Xu | 2017-11-30 18:25:47 -0600 |
commit | 99b73be3a8f3a97ff11f3e50a4169292a2f36fb1 (patch) | |
tree | e9880840a1c77ce51810def4d873dad21e5fa9b8 | |
parent | 5ce9fe355caf09efdb3679bec620ee486cedb731 (diff) | |
download | platform-bootable-recovery-99b73be3a8f3a97ff11f3e50a4169292a2f36fb1.tar.gz platform-bootable-recovery-99b73be3a8f3a97ff11f3e50a4169292a2f36fb1.tar.xz platform-bootable-recovery-99b73be3a8f3a97ff11f3e50a4169292a2f36fb1.zip |
Detect interrupted update due to power off
An interrupted update may stash extra blocks in /cache, leading to a
failure when checking the cache size. We can save the incremented
retry_count in the BCB before installing the update; and distinguish
a fresh update from an interrupted one this way.
Bug: 68679601
Test: An interrupted update reapplies successfully.
Change-Id: Ic1403e1fd25a937c91ef34c14b92a0f6c8f1c0f4
-rw-r--r-- | recovery.cpp | 565 | ||||
-rw-r--r-- | updater/install.cpp | 6 |
2 files changed, 302 insertions, 269 deletions
diff --git a/recovery.cpp b/recovery.cpp index a8991633..6bd29146 100644 --- a/recovery.cpp +++ b/recovery.cpp | |||
@@ -1313,6 +1313,7 @@ static bool is_battery_ok() { | |||
1313 | } | 1313 | } |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | // Set the retry count to |retry_count| in BCB. | ||
1316 | static void set_retry_bootloader_message(int retry_count, const std::vector<std::string>& args) { | 1317 | static void set_retry_bootloader_message(int retry_count, const std::vector<std::string>& args) { |
1317 | std::vector<std::string> options; | 1318 | std::vector<std::string> options; |
1318 | for (const auto& arg : args) { | 1319 | for (const auto& arg : args) { |
@@ -1321,8 +1322,8 @@ static void set_retry_bootloader_message(int retry_count, const std::vector<std: | |||
1321 | } | 1322 | } |
1322 | } | 1323 | } |
1323 | 1324 | ||
1324 | // Increment the retry counter by 1. | 1325 | // Update the retry counter in BCB. |
1325 | options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count + 1)); | 1326 | options.push_back(android::base::StringPrintf("--retry_count=%d", retry_count)); |
1326 | std::string err; | 1327 | std::string err; |
1327 | if (!update_bootloader_message(options, &err)) { | 1328 | if (!update_bootloader_message(options, &err)) { |
1328 | LOG(ERROR) << err; | 1329 | LOG(ERROR) << err; |
@@ -1357,303 +1358,331 @@ static void log_failure_code(ErrorCode code, const char *update_package) { | |||
1357 | } | 1358 | } |
1358 | 1359 | ||
1359 | int main(int argc, char **argv) { | 1360 | int main(int argc, char **argv) { |
1360 | // We don't have logcat yet under recovery; so we'll print error on screen and | 1361 | // We don't have logcat yet under recovery; so we'll print error on screen and |
1361 | // log to stdout (which is redirected to recovery.log) as we used to do. | 1362 | // log to stdout (which is redirected to recovery.log) as we used to do. |
1362 | android::base::InitLogging(argv, &UiLogger); | 1363 | android::base::InitLogging(argv, &UiLogger); |
1363 | 1364 | ||
1364 | // Take last pmsg contents and rewrite it to the current pmsg session. | 1365 | // Take last pmsg contents and rewrite it to the current pmsg session. |
1365 | static const char filter[] = "recovery/"; | 1366 | static const char filter[] = "recovery/"; |
1366 | // Do we need to rotate? | 1367 | // Do we need to rotate? |
1367 | bool doRotate = false; | 1368 | bool doRotate = false; |
1368 | 1369 | ||
1369 | __android_log_pmsg_file_read( | 1370 | __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &doRotate); |
1370 | LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, | 1371 | // Take action to refresh pmsg contents |
1371 | logbasename, &doRotate); | 1372 | __android_log_pmsg_file_read(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &doRotate); |
1372 | // Take action to refresh pmsg contents | 1373 | |
1373 | __android_log_pmsg_file_read( | 1374 | // If this binary is started with the single argument "--adbd", |
1374 | LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, | 1375 | // instead of being the normal recovery binary, it turns into kind |
1375 | logrotate, &doRotate); | 1376 | // of a stripped-down version of adbd that only supports the |
1376 | 1377 | // 'sideload' command. Note this must be a real argument, not | |
1377 | // If this binary is started with the single argument "--adbd", | 1378 | // anything in the command file or bootloader control block; the |
1378 | // instead of being the normal recovery binary, it turns into kind | 1379 | // only way recovery should be run with this argument is when it |
1379 | // of a stripped-down version of adbd that only supports the | 1380 | // starts a copy of itself from the apply_from_adb() function. |
1380 | // 'sideload' command. Note this must be a real argument, not | 1381 | if (argc == 2 && strcmp(argv[1], "--adbd") == 0) { |
1381 | // anything in the command file or bootloader control block; the | 1382 | minadbd_main(); |
1382 | // only way recovery should be run with this argument is when it | 1383 | return 0; |
1383 | // starts a copy of itself from the apply_from_adb() function. | 1384 | } |
1384 | if (argc == 2 && strcmp(argv[1], "--adbd") == 0) { | 1385 | |
1385 | minadbd_main(); | 1386 | time_t start = time(nullptr); |
1386 | return 0; | 1387 | |
1387 | } | 1388 | // redirect_stdio should be called only in non-sideload mode. Otherwise |
1388 | 1389 | // we may have two logger instances with different timestamps. | |
1389 | time_t start = time(NULL); | 1390 | redirect_stdio(TEMPORARY_LOG_FILE); |
1390 | 1391 | ||
1391 | // redirect_stdio should be called only in non-sideload mode. Otherwise | 1392 | printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start)); |
1392 | // we may have two logger instances with different timestamps. | 1393 | |
1393 | redirect_stdio(TEMPORARY_LOG_FILE); | 1394 | load_volume_table(); |
1394 | 1395 | has_cache = volume_for_mount_point(CACHE_ROOT) != nullptr; | |
1395 | printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start)); | 1396 | |
1396 | 1397 | std::vector<std::string> args = get_args(argc, argv); | |
1397 | load_volume_table(); | 1398 | std::vector<char*> args_to_parse(args.size()); |
1398 | has_cache = volume_for_mount_point(CACHE_ROOT) != nullptr; | 1399 | std::transform(args.cbegin(), args.cend(), args_to_parse.begin(), |
1399 | 1400 | [](const std::string& arg) { return const_cast<char*>(arg.c_str()); }); | |
1400 | std::vector<std::string> args = get_args(argc, argv); | 1401 | |
1401 | std::vector<char*> args_to_parse(args.size()); | 1402 | const char* update_package = nullptr; |
1402 | std::transform(args.cbegin(), args.cend(), args_to_parse.begin(), | 1403 | bool should_wipe_data = false; |
1403 | [](const std::string& arg) { return const_cast<char*>(arg.c_str()); }); | 1404 | bool should_prompt_and_wipe_data = false; |
1404 | 1405 | bool should_wipe_cache = false; | |
1405 | const char *update_package = NULL; | 1406 | bool should_wipe_ab = false; |
1406 | bool should_wipe_data = false; | 1407 | size_t wipe_package_size = 0; |
1407 | bool should_prompt_and_wipe_data = false; | 1408 | bool show_text = false; |
1408 | bool should_wipe_cache = false; | 1409 | bool sideload = false; |
1409 | bool should_wipe_ab = false; | 1410 | bool sideload_auto_reboot = false; |
1410 | size_t wipe_package_size = 0; | 1411 | bool just_exit = false; |
1411 | bool show_text = false; | 1412 | bool shutdown_after = false; |
1412 | bool sideload = false; | 1413 | int retry_count = 0; |
1413 | bool sideload_auto_reboot = false; | 1414 | bool security_update = false; |
1414 | bool just_exit = false; | 1415 | |
1415 | bool shutdown_after = false; | 1416 | int arg; |
1416 | int retry_count = 0; | 1417 | int option_index; |
1417 | bool security_update = false; | 1418 | while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS, |
1418 | 1419 | &option_index)) != -1) { | |
1419 | int arg; | 1420 | switch (arg) { |
1420 | int option_index; | 1421 | case 'n': |
1421 | while ((arg = getopt_long(args_to_parse.size(), args_to_parse.data(), "", OPTIONS, | 1422 | android::base::ParseInt(optarg, &retry_count, 0); |
1422 | &option_index)) != -1) { | 1423 | break; |
1423 | switch (arg) { | 1424 | case 'u': |
1424 | case 'n': android::base::ParseInt(optarg, &retry_count, 0); break; | 1425 | update_package = optarg; |
1425 | case 'u': update_package = optarg; break; | 1426 | break; |
1426 | case 'w': should_wipe_data = true; break; | 1427 | case 'w': |
1427 | case 'c': should_wipe_cache = true; break; | 1428 | should_wipe_data = true; |
1428 | case 't': show_text = true; break; | 1429 | break; |
1429 | case 's': sideload = true; break; | 1430 | case 'c': |
1430 | case 'a': sideload = true; sideload_auto_reboot = true; break; | 1431 | should_wipe_cache = true; |
1431 | case 'x': just_exit = true; break; | 1432 | break; |
1432 | case 'l': locale = optarg; break; | 1433 | case 't': |
1433 | case 'p': shutdown_after = true; break; | 1434 | show_text = true; |
1434 | case 'r': reason = optarg; break; | 1435 | break; |
1435 | case 'e': security_update = true; break; | 1436 | case 's': |
1436 | case 0: { | 1437 | sideload = true; |
1437 | std::string option = OPTIONS[option_index].name; | 1438 | break; |
1438 | if (option == "wipe_ab") { | 1439 | case 'a': |
1439 | should_wipe_ab = true; | 1440 | sideload = true; |
1440 | } else if (option == "wipe_package_size") { | 1441 | sideload_auto_reboot = true; |
1441 | android::base::ParseUint(optarg, &wipe_package_size); | 1442 | break; |
1442 | } else if (option == "prompt_and_wipe_data") { | 1443 | case 'x': |
1443 | should_prompt_and_wipe_data = true; | 1444 | just_exit = true; |
1444 | } | 1445 | break; |
1445 | break; | 1446 | case 'l': |
1446 | } | 1447 | locale = optarg; |
1447 | case '?': | 1448 | break; |
1448 | LOG(ERROR) << "Invalid command argument"; | 1449 | case 'p': |
1449 | continue; | 1450 | shutdown_after = true; |
1451 | break; | ||
1452 | case 'r': | ||
1453 | reason = optarg; | ||
1454 | break; | ||
1455 | case 'e': | ||
1456 | security_update = true; | ||
1457 | break; | ||
1458 | case 0: { | ||
1459 | std::string option = OPTIONS[option_index].name; | ||
1460 | if (option == "wipe_ab") { | ||
1461 | should_wipe_ab = true; | ||
1462 | } else if (option == "wipe_package_size") { | ||
1463 | android::base::ParseUint(optarg, &wipe_package_size); | ||
1464 | } else if (option == "prompt_and_wipe_data") { | ||
1465 | should_prompt_and_wipe_data = true; | ||
1450 | } | 1466 | } |
1467 | break; | ||
1468 | } | ||
1469 | case '?': | ||
1470 | LOG(ERROR) << "Invalid command argument"; | ||
1471 | continue; | ||
1451 | } | 1472 | } |
1473 | } | ||
1452 | 1474 | ||
1453 | if (locale.empty()) { | 1475 | if (locale.empty()) { |
1454 | if (has_cache) { | 1476 | if (has_cache) { |
1455 | locale = load_locale_from_cache(); | 1477 | locale = load_locale_from_cache(); |
1456 | } | 1478 | } |
1457 | 1479 | ||
1458 | if (locale.empty()) { | 1480 | if (locale.empty()) { |
1459 | locale = DEFAULT_LOCALE; | 1481 | locale = DEFAULT_LOCALE; |
1460 | } | ||
1461 | } | 1482 | } |
1483 | } | ||
1462 | 1484 | ||
1463 | printf("locale is [%s]\n", locale.c_str()); | 1485 | printf("locale is [%s]\n", locale.c_str()); |
1464 | printf("stage is [%s]\n", stage.c_str()); | 1486 | printf("stage is [%s]\n", stage.c_str()); |
1465 | printf("reason is [%s]\n", reason); | 1487 | printf("reason is [%s]\n", reason); |
1466 | 1488 | ||
1467 | Device* device = make_device(); | 1489 | Device* device = make_device(); |
1468 | if (android::base::GetBoolProperty("ro.boot.quiescent", false)) { | 1490 | if (android::base::GetBoolProperty("ro.boot.quiescent", false)) { |
1469 | printf("Quiescent recovery mode.\n"); | 1491 | printf("Quiescent recovery mode.\n"); |
1470 | ui = new StubRecoveryUI(); | 1492 | ui = new StubRecoveryUI(); |
1471 | } else { | 1493 | } else { |
1472 | ui = device->GetUI(); | 1494 | ui = device->GetUI(); |
1473 | 1495 | ||
1474 | if (!ui->Init(locale)) { | 1496 | if (!ui->Init(locale)) { |
1475 | printf("Failed to initialize UI, use stub UI instead.\n"); | 1497 | printf("Failed to initialize UI, use stub UI instead.\n"); |
1476 | ui = new StubRecoveryUI(); | 1498 | ui = new StubRecoveryUI(); |
1477 | } | ||
1478 | } | 1499 | } |
1500 | } | ||
1479 | 1501 | ||
1480 | // Set background string to "installing security update" for security update, | 1502 | // Set background string to "installing security update" for security update, |
1481 | // otherwise set it to "installing system update". | 1503 | // otherwise set it to "installing system update". |
1482 | ui->SetSystemUpdateText(security_update); | 1504 | ui->SetSystemUpdateText(security_update); |
1483 | 1505 | ||
1484 | int st_cur, st_max; | 1506 | int st_cur, st_max; |
1485 | if (!stage.empty() && sscanf(stage.c_str(), "%d/%d", &st_cur, &st_max) == 2) { | 1507 | if (!stage.empty() && sscanf(stage.c_str(), "%d/%d", &st_cur, &st_max) == 2) { |
1486 | ui->SetStage(st_cur, st_max); | 1508 | ui->SetStage(st_cur, st_max); |
1487 | } | 1509 | } |
1488 | 1510 | ||
1489 | ui->SetBackground(RecoveryUI::NONE); | 1511 | ui->SetBackground(RecoveryUI::NONE); |
1490 | if (show_text) ui->ShowText(true); | 1512 | if (show_text) ui->ShowText(true); |
1491 | 1513 | ||
1492 | sehandle = selinux_android_file_context_handle(); | 1514 | sehandle = selinux_android_file_context_handle(); |
1493 | selinux_android_set_sehandle(sehandle); | 1515 | selinux_android_set_sehandle(sehandle); |
1494 | if (!sehandle) { | 1516 | if (!sehandle) { |
1495 | ui->Print("Warning: No file_contexts\n"); | 1517 | ui->Print("Warning: No file_contexts\n"); |
1496 | } | 1518 | } |
1497 | 1519 | ||
1498 | device->StartRecovery(); | 1520 | device->StartRecovery(); |
1499 | 1521 | ||
1500 | printf("Command:"); | 1522 | printf("Command:"); |
1501 | for (const auto& arg : args) { | 1523 | for (const auto& arg : args) { |
1502 | printf(" \"%s\"", arg.c_str()); | 1524 | printf(" \"%s\"", arg.c_str()); |
1503 | } | 1525 | } |
1504 | printf("\n\n"); | 1526 | printf("\n\n"); |
1505 | 1527 | ||
1506 | property_list(print_property, NULL); | 1528 | property_list(print_property, nullptr); |
1507 | printf("\n"); | 1529 | printf("\n"); |
1508 | 1530 | ||
1509 | ui->Print("Supported API: %d\n", kRecoveryApiVersion); | 1531 | ui->Print("Supported API: %d\n", kRecoveryApiVersion); |
1510 | 1532 | ||
1511 | int status = INSTALL_SUCCESS; | 1533 | int status = INSTALL_SUCCESS; |
1512 | 1534 | ||
1513 | if (update_package != NULL) { | 1535 | if (update_package != nullptr) { |
1514 | // It's not entirely true that we will modify the flash. But we want | 1536 | // It's not entirely true that we will modify the flash. But we want |
1515 | // to log the update attempt since update_package is non-NULL. | 1537 | // to log the update attempt since update_package is non-NULL. |
1516 | modified_flash = true; | 1538 | modified_flash = true; |
1517 | 1539 | ||
1518 | if (!is_battery_ok()) { | 1540 | if (!is_battery_ok()) { |
1519 | ui->Print("battery capacity is not enough for installing package, needed is %d%%\n", | 1541 | ui->Print("battery capacity is not enough for installing package, needed is %d%%\n", |
1520 | BATTERY_OK_PERCENTAGE); | 1542 | BATTERY_OK_PERCENTAGE); |
1521 | // Log the error code to last_install when installation skips due to | 1543 | // Log the error code to last_install when installation skips due to |
1522 | // low battery. | 1544 | // low battery. |
1523 | log_failure_code(kLowBattery, update_package); | 1545 | log_failure_code(kLowBattery, update_package); |
1524 | status = INSTALL_SKIPPED; | 1546 | status = INSTALL_SKIPPED; |
1525 | } else if (bootreason_in_blacklist()) { | 1547 | } else if (bootreason_in_blacklist()) { |
1526 | // Skip update-on-reboot when bootreason is kernel_panic or similar | 1548 | // Skip update-on-reboot when bootreason is kernel_panic or similar |
1527 | ui->Print("bootreason is in the blacklist; skip OTA installation\n"); | 1549 | ui->Print("bootreason is in the blacklist; skip OTA installation\n"); |
1528 | log_failure_code(kBootreasonInBlacklist, update_package); | 1550 | log_failure_code(kBootreasonInBlacklist, update_package); |
1529 | status = INSTALL_SKIPPED; | 1551 | status = INSTALL_SKIPPED; |
1530 | } else { | 1552 | } else { |
1531 | status = install_package(update_package, &should_wipe_cache, | 1553 | // It's a fresh update. Initialize the retry_count in the BCB to 1; therefore we can later |
1532 | TEMPORARY_INSTALL_FILE, true, retry_count); | 1554 | // identify the interrupted update due to unexpected reboots. |
1533 | if (status == INSTALL_SUCCESS && should_wipe_cache) { | 1555 | if (retry_count == 0) { |
1534 | wipe_cache(false, device); | 1556 | set_retry_bootloader_message(retry_count + 1, args); |
1535 | } | 1557 | } |
1536 | if (status != INSTALL_SUCCESS) { | 1558 | |
1537 | ui->Print("Installation aborted.\n"); | 1559 | status = install_package(update_package, &should_wipe_cache, TEMPORARY_INSTALL_FILE, true, |
1538 | // When I/O error happens, reboot and retry installation RETRY_LIMIT | 1560 | retry_count); |
1539 | // times before we abandon this OTA update. | 1561 | if (status == INSTALL_SUCCESS && should_wipe_cache) { |
1540 | if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) { | 1562 | wipe_cache(false, device); |
1541 | copy_logs(); | 1563 | } |
1542 | set_retry_bootloader_message(retry_count, args); | 1564 | if (status != INSTALL_SUCCESS) { |
1543 | // Print retry count on screen. | 1565 | ui->Print("Installation aborted.\n"); |
1544 | ui->Print("Retry attempt %d\n", retry_count); | 1566 | // When I/O error happens, reboot and retry installation RETRY_LIMIT |
1545 | 1567 | // times before we abandon this OTA update. | |
1546 | // Reboot and retry the update | 1568 | if (status == INSTALL_RETRY && retry_count < RETRY_LIMIT) { |
1547 | if (!reboot("reboot,recovery")) { | 1569 | copy_logs(); |
1548 | ui->Print("Reboot failed\n"); | 1570 | retry_count += 1; |
1549 | } else { | 1571 | set_retry_bootloader_message(retry_count, args); |
1550 | while (true) { | 1572 | // Print retry count on screen. |
1551 | pause(); | 1573 | ui->Print("Retry attempt %d\n", retry_count); |
1552 | } | 1574 | |
1553 | } | 1575 | // Reboot and retry the update |
1554 | } | 1576 | if (!reboot("reboot,recovery")) { |
1555 | // If this is an eng or userdebug build, then automatically | 1577 | ui->Print("Reboot failed\n"); |
1556 | // turn the text display on if the script fails so the error | 1578 | } else { |
1557 | // message is visible. | 1579 | while (true) { |
1558 | if (is_ro_debuggable()) { | 1580 | pause(); |
1559 | ui->ShowText(true); | ||
1560 | } | ||
1561 | } | ||
1562 | } | ||
1563 | } else if (should_wipe_data) { | ||
1564 | if (!wipe_data(device)) { | ||
1565 | status = INSTALL_ERROR; | ||
1566 | } | ||
1567 | } else if (should_prompt_and_wipe_data) { | ||
1568 | ui->ShowText(true); | ||
1569 | ui->SetBackground(RecoveryUI::ERROR); | ||
1570 | if (!prompt_and_wipe_data(device)) { | ||
1571 | status = INSTALL_ERROR; | ||
1572 | } | ||
1573 | ui->ShowText(false); | ||
1574 | } else if (should_wipe_cache) { | ||
1575 | if (!wipe_cache(false, device)) { | ||
1576 | status = INSTALL_ERROR; | ||
1577 | } | ||
1578 | } else if (should_wipe_ab) { | ||
1579 | if (!wipe_ab_device(wipe_package_size)) { | ||
1580 | status = INSTALL_ERROR; | ||
1581 | } | ||
1582 | } else if (sideload) { | ||
1583 | // 'adb reboot sideload' acts the same as user presses key combinations | ||
1584 | // to enter the sideload mode. When 'sideload-auto-reboot' is used, text | ||
1585 | // display will NOT be turned on by default. And it will reboot after | ||
1586 | // sideload finishes even if there are errors. Unless one turns on the | ||
1587 | // text display during the installation. This is to enable automated | ||
1588 | // testing. | ||
1589 | if (!sideload_auto_reboot) { | ||
1590 | ui->ShowText(true); | ||
1591 | } | ||
1592 | status = apply_from_adb(&should_wipe_cache, TEMPORARY_INSTALL_FILE); | ||
1593 | if (status == INSTALL_SUCCESS && should_wipe_cache) { | ||
1594 | if (!wipe_cache(false, device)) { | ||
1595 | status = INSTALL_ERROR; | ||
1596 | } | 1581 | } |
1582 | } | ||
1597 | } | 1583 | } |
1598 | ui->Print("\nInstall from ADB complete (status: %d).\n", status); | 1584 | // If this is an eng or userdebug build, then automatically |
1599 | if (sideload_auto_reboot) { | 1585 | // turn the text display on if the script fails so the error |
1600 | ui->Print("Rebooting automatically.\n"); | 1586 | // message is visible. |
1587 | if (is_ro_debuggable()) { | ||
1588 | ui->ShowText(true); | ||
1601 | } | 1589 | } |
1602 | } else if (!just_exit) { | ||
1603 | // If this is an eng or userdebug build, automatically turn on the text display if no command | ||
1604 | // is specified. Note that this should be called before setting the background to avoid | ||
1605 | // flickering the background image. | ||
1606 | if (is_ro_debuggable()) { | ||
1607 | ui->ShowText(true); | ||
1608 | } | 1590 | } |
1609 | status = INSTALL_NONE; // No command specified | ||
1610 | ui->SetBackground(RecoveryUI::NO_COMMAND); | ||
1611 | } | 1591 | } |
1592 | } else if (should_wipe_data) { | ||
1593 | if (!wipe_data(device)) { | ||
1594 | status = INSTALL_ERROR; | ||
1595 | } | ||
1596 | } else if (should_prompt_and_wipe_data) { | ||
1597 | ui->ShowText(true); | ||
1598 | ui->SetBackground(RecoveryUI::ERROR); | ||
1599 | if (!prompt_and_wipe_data(device)) { | ||
1600 | status = INSTALL_ERROR; | ||
1601 | } | ||
1602 | ui->ShowText(false); | ||
1603 | } else if (should_wipe_cache) { | ||
1604 | if (!wipe_cache(false, device)) { | ||
1605 | status = INSTALL_ERROR; | ||
1606 | } | ||
1607 | } else if (should_wipe_ab) { | ||
1608 | if (!wipe_ab_device(wipe_package_size)) { | ||
1609 | status = INSTALL_ERROR; | ||
1610 | } | ||
1611 | } else if (sideload) { | ||
1612 | // 'adb reboot sideload' acts the same as user presses key combinations | ||
1613 | // to enter the sideload mode. When 'sideload-auto-reboot' is used, text | ||
1614 | // display will NOT be turned on by default. And it will reboot after | ||
1615 | // sideload finishes even if there are errors. Unless one turns on the | ||
1616 | // text display during the installation. This is to enable automated | ||
1617 | // testing. | ||
1618 | if (!sideload_auto_reboot) { | ||
1619 | ui->ShowText(true); | ||
1620 | } | ||
1621 | status = apply_from_adb(&should_wipe_cache, TEMPORARY_INSTALL_FILE); | ||
1622 | if (status == INSTALL_SUCCESS && should_wipe_cache) { | ||
1623 | if (!wipe_cache(false, device)) { | ||
1624 | status = INSTALL_ERROR; | ||
1625 | } | ||
1626 | } | ||
1627 | ui->Print("\nInstall from ADB complete (status: %d).\n", status); | ||
1628 | if (sideload_auto_reboot) { | ||
1629 | ui->Print("Rebooting automatically.\n"); | ||
1630 | } | ||
1631 | } else if (!just_exit) { | ||
1632 | // If this is an eng or userdebug build, automatically turn on the text display if no command | ||
1633 | // is specified. Note that this should be called before setting the background to avoid | ||
1634 | // flickering the background image. | ||
1635 | if (is_ro_debuggable()) { | ||
1636 | ui->ShowText(true); | ||
1637 | } | ||
1638 | status = INSTALL_NONE; // No command specified | ||
1639 | ui->SetBackground(RecoveryUI::NO_COMMAND); | ||
1640 | } | ||
1612 | 1641 | ||
1613 | if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { | 1642 | if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { |
1614 | ui->SetBackground(RecoveryUI::ERROR); | 1643 | ui->SetBackground(RecoveryUI::ERROR); |
1615 | if (!ui->IsTextVisible()) { | 1644 | if (!ui->IsTextVisible()) { |
1616 | sleep(5); | 1645 | sleep(5); |
1617 | } | ||
1618 | } | 1646 | } |
1647 | } | ||
1619 | 1648 | ||
1620 | Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT; | 1649 | Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT; |
1621 | // 1. If the recovery menu is visible, prompt and wait for commands. | 1650 | // 1. If the recovery menu is visible, prompt and wait for commands. |
1622 | // 2. If the state is INSTALL_NONE, wait for commands. (i.e. In user build, manually reboot into | 1651 | // 2. If the state is INSTALL_NONE, wait for commands. (i.e. In user build, manually reboot into |
1623 | // recovery to sideload a package.) | 1652 | // recovery to sideload a package.) |
1624 | // 3. sideload_auto_reboot is an option only available in user-debug build, reboot the device | 1653 | // 3. sideload_auto_reboot is an option only available in user-debug build, reboot the device |
1625 | // without waiting. | 1654 | // without waiting. |
1626 | // 4. In all other cases, reboot the device. Therefore, normal users will observe the device | 1655 | // 4. In all other cases, reboot the device. Therefore, normal users will observe the device |
1627 | // reboot after it shows the "error" screen for 5s. | 1656 | // reboot after it shows the "error" screen for 5s. |
1628 | if ((status == INSTALL_NONE && !sideload_auto_reboot) || ui->IsTextVisible()) { | 1657 | if ((status == INSTALL_NONE && !sideload_auto_reboot) || ui->IsTextVisible()) { |
1629 | Device::BuiltinAction temp = prompt_and_wait(device, status); | 1658 | Device::BuiltinAction temp = prompt_and_wait(device, status); |
1630 | if (temp != Device::NO_ACTION) { | 1659 | if (temp != Device::NO_ACTION) { |
1631 | after = temp; | 1660 | after = temp; |
1632 | } | ||
1633 | } | 1661 | } |
1662 | } | ||
1634 | 1663 | ||
1635 | // Save logs and clean up before rebooting or shutting down. | 1664 | // Save logs and clean up before rebooting or shutting down. |
1636 | finish_recovery(); | 1665 | finish_recovery(); |
1637 | 1666 | ||
1638 | switch (after) { | 1667 | switch (after) { |
1639 | case Device::SHUTDOWN: | 1668 | case Device::SHUTDOWN: |
1640 | ui->Print("Shutting down...\n"); | 1669 | ui->Print("Shutting down...\n"); |
1641 | android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,"); | 1670 | android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,"); |
1642 | break; | 1671 | break; |
1643 | 1672 | ||
1644 | case Device::REBOOT_BOOTLOADER: | 1673 | case Device::REBOOT_BOOTLOADER: |
1645 | ui->Print("Rebooting to bootloader...\n"); | 1674 | ui->Print("Rebooting to bootloader...\n"); |
1646 | android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); | 1675 | android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader"); |
1647 | break; | 1676 | break; |
1648 | 1677 | ||
1649 | default: | 1678 | default: |
1650 | ui->Print("Rebooting...\n"); | 1679 | ui->Print("Rebooting...\n"); |
1651 | reboot("reboot,"); | 1680 | reboot("reboot,"); |
1652 | break; | 1681 | break; |
1653 | } | 1682 | } |
1654 | while (true) { | 1683 | while (true) { |
1655 | pause(); | 1684 | pause(); |
1656 | } | 1685 | } |
1657 | // Should be unreachable. | 1686 | // Should be unreachable. |
1658 | return EXIT_SUCCESS; | 1687 | return EXIT_SUCCESS; |
1659 | } | 1688 | } |
diff --git a/updater/install.cpp b/updater/install.cpp index a111f4b7..870b8579 100644 --- a/updater/install.cpp +++ b/updater/install.cpp | |||
@@ -569,7 +569,11 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, const std::vector<std:: | |||
569 | name, bytes_str.c_str()); | 569 | name, bytes_str.c_str()); |
570 | } | 570 | } |
571 | 571 | ||
572 | return StringValue(CacheSizeCheck(bytes) ? "" : "t"); | 572 | // Skip the cache size check if the update is a retry. |
573 | if (state->is_retry || CacheSizeCheck(bytes) == 0) { | ||
574 | return StringValue("t"); | ||
575 | } | ||
576 | return StringValue(""); | ||
573 | } | 577 | } |
574 | 578 | ||
575 | // apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...]) | 579 | // apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...]) |