Snap for 4954221 from 95d7e47d01 to qt-release
Change-Id: If786cc7e4e3efdbd017f003d2028fd9044efbbe8
This commit is contained in:
+30
-14
@@ -96,6 +96,29 @@ cc_library_static {
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "librecovery_fastboot",
|
||||
recovery_available: true,
|
||||
defaults: [
|
||||
"recovery_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"fastboot/fastboot.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbootloader_message",
|
||||
"libcutils",
|
||||
"liblog",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"librecovery_ui_default",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "librecovery_defaults",
|
||||
|
||||
@@ -104,19 +127,20 @@ cc_defaults {
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"android.hardware.health@2.0",
|
||||
"libbase",
|
||||
"libbootloader_message",
|
||||
"libcrypto",
|
||||
"libcrypto_utils",
|
||||
"libcutils",
|
||||
"libext4_utils",
|
||||
"libfs_mgr",
|
||||
"libfusesideload",
|
||||
"libhidl-gen-utils",
|
||||
"libhidlbase",
|
||||
"libhidltransport",
|
||||
"liblog",
|
||||
"libpng",
|
||||
"libselinux",
|
||||
"libsparse",
|
||||
"libtinyxml2",
|
||||
"libutils",
|
||||
"libz",
|
||||
@@ -124,23 +148,15 @@ cc_defaults {
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"librecovery_fastboot",
|
||||
"libminui",
|
||||
"libverifier",
|
||||
"libotautil",
|
||||
|
||||
// external dependencies
|
||||
"libhealthhalutils",
|
||||
"libvintf_recovery",
|
||||
"libvintf",
|
||||
|
||||
// TODO(b/80132328): Remove the dependency on static health HAL.
|
||||
"libhealthd.default",
|
||||
"android.hardware.health@2.0-impl",
|
||||
"android.hardware.health@2.0",
|
||||
"android.hardware.health@1.0",
|
||||
"android.hardware.health@1.0-convert",
|
||||
"libhealthstoragedefault",
|
||||
"libhidltransport",
|
||||
"libhidlbase",
|
||||
"libhwbinder_noltopgo",
|
||||
"libbatterymonitor",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# Needed by build/make/core/Makefile.
|
||||
# Needed by build/make/core/Makefile. Must be consistent with the value in Android.bp.
|
||||
RECOVERY_API_VERSION := 3
|
||||
RECOVERY_FSTAB_VERSION := 2
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
static std::vector<std::pair<std::string, Device::BuiltinAction>> g_menu_actions{
|
||||
{ "Reboot system now", Device::REBOOT },
|
||||
{ "Reboot to bootloader", Device::REBOOT_BOOTLOADER },
|
||||
{ "Enter fastboot", Device::ENTER_FASTBOOT },
|
||||
{ "Apply update from ADB", Device::APPLY_ADB_SIDELOAD },
|
||||
{ "Apply update from SD card", Device::APPLY_SDCARD },
|
||||
{ "Wipe data/factory reset", Device::WIPE_DATA },
|
||||
|
||||
@@ -48,6 +48,8 @@ class Device {
|
||||
RUN_GRAPHICS_TEST = 11,
|
||||
RUN_LOCALE_TEST = 12,
|
||||
KEY_INTERRUPTED = 13,
|
||||
ENTER_FASTBOOT = 14,
|
||||
ENTER_RECOVERY = 15,
|
||||
};
|
||||
|
||||
explicit Device(RecoveryUI* ui);
|
||||
|
||||
+84
-19
@@ -6,6 +6,8 @@ on early-init
|
||||
|
||||
start ueventd
|
||||
|
||||
setprop sys.usb.configfs 0
|
||||
|
||||
on init
|
||||
export ANDROID_ROOT /system
|
||||
export ANDROID_DATA /data
|
||||
@@ -31,20 +33,6 @@ on init
|
||||
write /proc/sys/kernel/panic_on_oops 1
|
||||
write /proc/sys/vm/max_map_count 1000000
|
||||
|
||||
on fs
|
||||
write /sys/class/android_usb/android0/f_ffs/aliases adb
|
||||
mkdir /dev/usb-ffs 0770 shell shell
|
||||
mkdir /dev/usb-ffs/adb 0770 shell shell
|
||||
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
|
||||
|
||||
write /sys/class/android_usb/android0/enable 0
|
||||
write /sys/class/android_usb/android0/idVendor 18D1
|
||||
write /sys/class/android_usb/android0/idProduct D001
|
||||
write /sys/class/android_usb/android0/functions adb
|
||||
write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
|
||||
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
|
||||
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
|
||||
|
||||
on boot
|
||||
ifup lo
|
||||
hostname localhost
|
||||
@@ -86,6 +74,7 @@ service charger /charger -r
|
||||
seclabel u:r:charger:s0
|
||||
|
||||
service recovery /system/bin/recovery
|
||||
socket recovery stream 422 system system
|
||||
seclabel u:r:recovery:s0
|
||||
|
||||
service adbd /system/bin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
|
||||
@@ -93,13 +82,89 @@ service adbd /system/bin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
|
||||
socket adbd stream 660 system system
|
||||
seclabel u:r:adbd:s0
|
||||
|
||||
# Always start adbd on userdebug and eng builds
|
||||
on property:ro.debuggable=1
|
||||
write /sys/class/android_usb/android0/enable 1
|
||||
start adbd
|
||||
service fastbootd /system/bin/fastbootd
|
||||
disabled
|
||||
group system
|
||||
seclabel u:r:fastbootd:s0
|
||||
|
||||
# Restart adbd so it can run as root
|
||||
on property:service.adb.root=1
|
||||
write /sys/class/android_usb/android0/enable 0
|
||||
restart adbd
|
||||
|
||||
# Always start adbd on userdebug and eng builds
|
||||
on fs && property:ro.debuggable=1
|
||||
setprop sys.usb.config adb
|
||||
|
||||
on fs && property:sys.usb.configfs=1
|
||||
mount configfs none /config
|
||||
mkdir /config/usb_gadget/g1 0770 shell shell
|
||||
write /config/usb_gadget/g1/idVendor 0x18D1
|
||||
mkdir /config/usb_gadget/g1/strings/0x409 0770
|
||||
write /config/usb_gadget/g1/strings/0x409/serialnumber ${ro.serialno}
|
||||
write /config/usb_gadget/g1/strings/0x409/manufacturer ${ro.product.manufacturer}
|
||||
write /config/usb_gadget/g1/strings/0x409/product ${ro.product.model}
|
||||
mkdir /config/usb_gadget/g1/functions/ffs.adb
|
||||
mkdir /config/usb_gadget/g1/functions/ffs.fastboot
|
||||
mkdir /config/usb_gadget/g1/configs/b.1 0777 shell shell
|
||||
mkdir /config/usb_gadget/g1/configs/b.1/strings/0x409 0770 shell shell
|
||||
|
||||
on fs && property:sys.usb.configfs=0
|
||||
write /sys/class/android_usb/android0/f_ffs/aliases adb,fastboot
|
||||
write /sys/class/android_usb/android0/idVendor 18D1
|
||||
write /sys/class/android_usb/android0/iManufacturer ${ro.product.manufacturer}
|
||||
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
|
||||
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
|
||||
|
||||
on fs
|
||||
mkdir /dev/usb-ffs 0775 shell shell
|
||||
mkdir /dev/usb-ffs/adb 0770 shell shell
|
||||
mount functionfs adb /dev/usb-ffs/adb uid=2000,gid=2000
|
||||
mkdir /dev/usb-ffs/fastboot 0770 system system
|
||||
mount functionfs fastboot /dev/usb-ffs/fastboot rmode=0770,fmode=0660,uid=1000,gid=1000
|
||||
|
||||
on property:sys.usb.config=adb
|
||||
start adbd
|
||||
|
||||
on property:sys.usb.config=fastboot
|
||||
start fastbootd
|
||||
|
||||
on property:sys.usb.config=none
|
||||
stop adbd
|
||||
stop fastbootd
|
||||
|
||||
on property:sys.usb.config=none && property:sys.usb.configfs=0
|
||||
write /sys/class/android_usb/android0/enable 0
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
on property:sys.usb.config=adb && property:sys.usb.configfs=0
|
||||
write /sys/class/android_usb/android0/idProduct D001
|
||||
write /sys/class/android_usb/android0/functions adb
|
||||
write /sys/class/android_usb/android0/enable 1
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
on property:sys.usb.config=fastboot && property:sys.usb.configfs=0
|
||||
write /sys/class/android_usb/android0/idProduct 4EE0
|
||||
write /sys/class/android_usb/android0/functions fastboot
|
||||
write /sys/class/android_usb/android0/enable 1
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
# Configfs triggers
|
||||
on property:sys.usb.config=none && property:sys.usb.configfs=1
|
||||
write /config/usb_gadget/g1/UDC "none"
|
||||
setprop sys.usb.ffs.ready 0
|
||||
rm /config/usb_gadget/g1/configs/b.1/f1
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
on property:sys.usb.config=adb && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
|
||||
write /config/usb_gadget/g1/idProduct 0xD001
|
||||
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
|
||||
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
|
||||
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
on property:sys.usb.config=fastboot && property:sys.usb.ffs.ready=1 && property:sys.usb.configfs=1
|
||||
write /config/usb_gadget/g1/idProduct 0x4EE0
|
||||
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "fastboot"
|
||||
symlink /config/usb_gadget/g1/functions/ffs.fastboot /config/usb_gadget/g1/configs/b.1/f1
|
||||
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
|
||||
setprop sys.usb.state ${sys.usb.config}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "fastboot.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <bootloader_message/bootloader_message.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "ui.h"
|
||||
|
||||
static const std::vector<std::pair<std::string, Device::BuiltinAction>> kFastbootMenuActions{
|
||||
{ "Reboot system now", Device::REBOOT },
|
||||
{ "Enter recovery", Device::ENTER_RECOVERY },
|
||||
{ "Reboot to bootloader", Device::REBOOT_BOOTLOADER },
|
||||
{ "Power off", Device::SHUTDOWN },
|
||||
};
|
||||
|
||||
Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& /* args */) {
|
||||
RecoveryUI* ui = device->GetUI();
|
||||
|
||||
std::vector<std::string> title_lines = { "Android Fastboot" };
|
||||
title_lines.push_back("Product name - " + android::base::GetProperty("ro.product.device", ""));
|
||||
title_lines.push_back("Bootloader version - " + android::base::GetProperty("ro.bootloader", ""));
|
||||
title_lines.push_back("Baseband version - " +
|
||||
android::base::GetProperty("ro.build.expect.baseband", ""));
|
||||
title_lines.push_back("Serial number - " + android::base::GetProperty("ro.serialno", ""));
|
||||
title_lines.push_back(std::string("Secure boot - ") +
|
||||
((android::base::GetProperty("ro.secure", "") == "1") ? "yes" : "no"));
|
||||
title_lines.push_back("HW version - " + android::base::GetProperty("ro.revision", ""));
|
||||
|
||||
ui->ResetKeyInterruptStatus();
|
||||
ui->SetTitle(title_lines);
|
||||
ui->ShowText(true);
|
||||
|
||||
// Reset to normal system boot so recovery won't cycle indefinitely.
|
||||
// TODO(b/112277594) Clear only if 'recovery' field of BCB is empty. If not,
|
||||
// set the 'command' field of BCB to 'boot-recovery' so the next boot is into recovery
|
||||
// to finish any interrupted tasks.
|
||||
std::string err;
|
||||
if (!clear_bootloader_message(&err)) {
|
||||
LOG(ERROR) << "Failed to clear BCB message: " << err;
|
||||
}
|
||||
|
||||
std::vector<std::string> fastboot_menu_items;
|
||||
std::transform(kFastbootMenuActions.cbegin(), kFastbootMenuActions.cend(),
|
||||
std::back_inserter(fastboot_menu_items),
|
||||
[](const auto& entry) { return entry.first; });
|
||||
|
||||
auto chosen_item = ui->ShowMenu(
|
||||
{}, fastboot_menu_items, 0, false,
|
||||
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
|
||||
return Device::KEY_INTERRUPTED;
|
||||
}
|
||||
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::TIMED_OUT)) {
|
||||
return Device::BuiltinAction::NO_ACTION;
|
||||
}
|
||||
return kFastbootMenuActions[chosen_item].second;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
Device::BuiltinAction StartFastboot(Device* device, const std::vector<std::string>& args);
|
||||
+30
-38
@@ -49,7 +49,7 @@
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <bootloader_message/bootloader_message.h>
|
||||
#include <cutils/properties.h> /* for property_list */
|
||||
#include <health2/Health.h>
|
||||
#include <healthhalutils/HealthHalUtils.h>
|
||||
#include <ziparchive/zip_archive.h>
|
||||
|
||||
#include "adb_install.h"
|
||||
@@ -779,6 +779,8 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
|
||||
case Device::REBOOT:
|
||||
case Device::SHUTDOWN:
|
||||
case Device::REBOOT_BOOTLOADER:
|
||||
case Device::ENTER_FASTBOOT:
|
||||
case Device::ENTER_RECOVERY:
|
||||
return chosen_action;
|
||||
|
||||
case Device::WIPE_DATA:
|
||||
@@ -877,42 +879,29 @@ void ui_print(const char* format, ...) {
|
||||
|
||||
static bool is_battery_ok(int* required_battery_level) {
|
||||
using android::hardware::health::V1_0::BatteryStatus;
|
||||
using android::hardware::health::V2_0::get_health_service;
|
||||
using android::hardware::health::V2_0::IHealth;
|
||||
using android::hardware::health::V2_0::Result;
|
||||
using android::hardware::health::V2_0::toString;
|
||||
using android::hardware::health::V2_0::implementation::Health;
|
||||
|
||||
struct healthd_config healthd_config = {
|
||||
.batteryStatusPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryHealthPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryPresentPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryCapacityPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryVoltagePath = android::String8(android::String8::kEmptyString),
|
||||
.batteryTemperaturePath = android::String8(android::String8::kEmptyString),
|
||||
.batteryTechnologyPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
|
||||
.batteryFullChargePath = android::String8(android::String8::kEmptyString),
|
||||
.batteryCycleCountPath = android::String8(android::String8::kEmptyString),
|
||||
.energyCounter = nullptr,
|
||||
.boot_min_cap = 0,
|
||||
.screen_on = nullptr
|
||||
};
|
||||
|
||||
auto health =
|
||||
android::hardware::health::V2_0::implementation::Health::initInstance(&healthd_config);
|
||||
android::sp<IHealth> health = get_health_service();
|
||||
|
||||
static constexpr int BATTERY_READ_TIMEOUT_IN_SEC = 10;
|
||||
int wait_second = 0;
|
||||
while (true) {
|
||||
auto charge_status = BatteryStatus::UNKNOWN;
|
||||
health
|
||||
->getChargeStatus([&charge_status](auto res, auto out_status) {
|
||||
if (res == Result::SUCCESS) {
|
||||
charge_status = out_status;
|
||||
}
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
|
||||
if (health == nullptr) {
|
||||
LOG(WARNING) << "no health implementation is found, assuming defaults";
|
||||
} else {
|
||||
health
|
||||
->getChargeStatus([&charge_status](auto res, auto out_status) {
|
||||
if (res == Result::SUCCESS) {
|
||||
charge_status = out_status;
|
||||
}
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
// Treat unknown status as charged.
|
||||
bool charged = (charge_status != BatteryStatus::DISCHARGING &&
|
||||
@@ -920,15 +909,17 @@ static bool is_battery_ok(int* required_battery_level) {
|
||||
|
||||
Result res = Result::UNKNOWN;
|
||||
int32_t capacity = INT32_MIN;
|
||||
health
|
||||
->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
|
||||
res = out_res;
|
||||
capacity = out_capacity;
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
if (health != nullptr) {
|
||||
health
|
||||
->getCapacity([&res, &capacity](auto out_res, auto out_capacity) {
|
||||
res = out_res;
|
||||
capacity = out_capacity;
|
||||
})
|
||||
.isOk(); // should not have transport error
|
||||
}
|
||||
|
||||
ui_print("charge_status %d, charged %d, status %s, capacity %" PRId32 "\n", charge_status,
|
||||
charged, toString(res).c_str(), capacity);
|
||||
LOG(INFO) << "charge_status " << toString(charge_status) << ", charged " << charged
|
||||
<< ", status " << toString(res) << ", capacity " << capacity;
|
||||
// At startup, the battery drivers in devices like N5X/N6P take some time to load
|
||||
// the battery profile. Before the load finishes, it reports value 50 as a fake
|
||||
// capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
|
||||
@@ -1006,6 +997,7 @@ static void log_failure_code(ErrorCode code, const std::string& update_package)
|
||||
|
||||
Device::BuiltinAction start_recovery(Device* device, const std::vector<std::string>& args) {
|
||||
static constexpr struct option OPTIONS[] = {
|
||||
{ "fastboot", no_argument, nullptr, 0 },
|
||||
{ "fsck_unshare_blocks", no_argument, nullptr, 0 },
|
||||
{ "just_exit", no_argument, nullptr, 'x' },
|
||||
{ "locale", required_argument, nullptr, 0 },
|
||||
@@ -1060,7 +1052,7 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri
|
||||
std::string option = OPTIONS[option_index].name;
|
||||
if (option == "fsck_unshare_blocks") {
|
||||
fsck_unshare_blocks = true;
|
||||
} else if (option == "locale") {
|
||||
} else if (option == "locale" || option == "fastboot") {
|
||||
// Handled in recovery_main.cpp
|
||||
} else if (option == "prompt_and_wipe_data") {
|
||||
should_prompt_and_wipe_data = true;
|
||||
|
||||
+104
-22
@@ -30,15 +30,19 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <bootloader_message/bootloader_message.h>
|
||||
#include <cutils/android_reboot.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <private/android_logger.h> /* private pmsg functions */
|
||||
#include <selinux/android.h>
|
||||
#include <selinux/label.h>
|
||||
@@ -46,6 +50,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
#include "fastboot/fastboot.h"
|
||||
#include "logging.h"
|
||||
#include "minadbd/minadbd.h"
|
||||
#include "otautil/paths.h"
|
||||
@@ -162,6 +167,44 @@ static std::string load_locale_from_cache() {
|
||||
return android::base::Trim(content);
|
||||
}
|
||||
|
||||
static void ListenRecoverySocket(RecoveryUI* ui, std::atomic<Device::BuiltinAction>& action) {
|
||||
android::base::unique_fd sock_fd(android_get_control_socket("recovery"));
|
||||
if (sock_fd < 0) {
|
||||
PLOG(ERROR) << "Failed to open recovery socket";
|
||||
return;
|
||||
}
|
||||
listen(sock_fd, 4);
|
||||
|
||||
while (true) {
|
||||
android::base::unique_fd connection_fd;
|
||||
connection_fd.reset(accept(sock_fd, nullptr, nullptr));
|
||||
if (connection_fd < 0) {
|
||||
PLOG(ERROR) << "Failed to accept socket connection";
|
||||
continue;
|
||||
}
|
||||
char msg;
|
||||
constexpr char kSwitchToFastboot = 'f';
|
||||
constexpr char kSwitchToRecovery = 'r';
|
||||
ssize_t ret = TEMP_FAILURE_RETRY(read(connection_fd, &msg, sizeof(msg)));
|
||||
if (ret != sizeof(msg)) {
|
||||
PLOG(ERROR) << "Couldn't read from socket";
|
||||
continue;
|
||||
}
|
||||
switch (msg) {
|
||||
case kSwitchToRecovery:
|
||||
action = Device::BuiltinAction::ENTER_RECOVERY;
|
||||
break;
|
||||
case kSwitchToFastboot:
|
||||
action = Device::BuiltinAction::ENTER_FASTBOOT;
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unrecognized char from socket " << msg;
|
||||
continue;
|
||||
}
|
||||
ui->InterruptKey();
|
||||
}
|
||||
}
|
||||
|
||||
static void redirect_stdio(const char* filename) {
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
@@ -251,6 +294,11 @@ static void redirect_stdio(const char* filename) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool SetUsbConfig(const std::string& state) {
|
||||
android::base::SetProperty("sys.usb.config", state);
|
||||
return android::base::WaitForProperty("sys.usb.state", state);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// We don't have logcat yet under recovery; so we'll print error on screen and log to stdout
|
||||
// (which is redirected to recovery.log) as we used to do.
|
||||
@@ -281,8 +329,6 @@ int main(int argc, char** argv) {
|
||||
// instances with different timestamps.
|
||||
redirect_stdio(Paths::Get().temporary_log_file().c_str());
|
||||
|
||||
printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
|
||||
|
||||
load_volume_table();
|
||||
has_cache = volume_for_mount_point(CACHE_ROOT) != nullptr;
|
||||
|
||||
@@ -290,12 +336,14 @@ int main(int argc, char** argv) {
|
||||
auto args_to_parse = StringVectorToNullTerminatedArray(args);
|
||||
|
||||
static constexpr struct option OPTIONS[] = {
|
||||
{ "fastboot", no_argument, nullptr, 0 },
|
||||
{ "locale", required_argument, nullptr, 0 },
|
||||
{ "show_text", no_argument, nullptr, 't' },
|
||||
{ nullptr, 0, nullptr, 0 },
|
||||
};
|
||||
|
||||
bool show_text = false;
|
||||
bool fastboot = false;
|
||||
std::string locale;
|
||||
|
||||
int arg;
|
||||
@@ -310,6 +358,8 @@ int main(int argc, char** argv) {
|
||||
std::string option = OPTIONS[option_index].name;
|
||||
if (option == "locale") {
|
||||
locale = optarg;
|
||||
} else if (option == "fastboot") {
|
||||
fastboot = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -328,8 +378,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
printf("locale is [%s]\n", locale.c_str());
|
||||
|
||||
static constexpr const char* kDefaultLibRecoveryUIExt = "librecovery_ui_ext.so";
|
||||
// Intentionally not calling dlclose(3) to avoid potential gotchas (e.g. `make_device` may have
|
||||
// handed out pointers to code or static [or thread-local] data and doesn't collect them all back
|
||||
@@ -374,33 +422,67 @@ int main(int argc, char** argv) {
|
||||
ui->SetBackground(RecoveryUI::NONE);
|
||||
if (show_text) ui->ShowText(true);
|
||||
|
||||
LOG(INFO) << "Starting recovery (pid " << getpid() << ") on " << ctime(&start);
|
||||
LOG(INFO) << "locale is [" << locale << "]";
|
||||
|
||||
sehandle = selinux_android_file_context_handle();
|
||||
selinux_android_set_sehandle(sehandle);
|
||||
if (!sehandle) {
|
||||
ui->Print("Warning: No file_contexts\n");
|
||||
}
|
||||
|
||||
Device::BuiltinAction after = start_recovery(device, args);
|
||||
std::atomic<Device::BuiltinAction> action;
|
||||
std::thread listener_thread(ListenRecoverySocket, ui, std::ref(action));
|
||||
listener_thread.detach();
|
||||
|
||||
switch (after) {
|
||||
case Device::SHUTDOWN:
|
||||
ui->Print("Shutting down...\n");
|
||||
android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,");
|
||||
break;
|
||||
|
||||
case Device::REBOOT_BOOTLOADER:
|
||||
ui->Print("Rebooting to bootloader...\n");
|
||||
android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
|
||||
break;
|
||||
|
||||
default:
|
||||
ui->Print("Rebooting...\n");
|
||||
reboot("reboot,");
|
||||
break;
|
||||
}
|
||||
while (true) {
|
||||
pause();
|
||||
std::string usb_config = fastboot ? "fastboot" : is_ro_debuggable() ? "adb" : "none";
|
||||
std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
|
||||
if (usb_config != usb_state) {
|
||||
if (!SetUsbConfig("none")) {
|
||||
LOG(ERROR) << "Failed to clear USB config";
|
||||
}
|
||||
if (!SetUsbConfig(usb_config)) {
|
||||
LOG(ERROR) << "Failed to set USB config to " << usb_config;
|
||||
}
|
||||
}
|
||||
|
||||
auto ret = fastboot ? StartFastboot(device, args) : start_recovery(device, args);
|
||||
|
||||
if (ret == Device::KEY_INTERRUPTED) {
|
||||
ret = action.exchange(ret);
|
||||
if (ret == Device::NO_ACTION) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch (ret) {
|
||||
case Device::SHUTDOWN:
|
||||
ui->Print("Shutting down...\n");
|
||||
android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,");
|
||||
break;
|
||||
|
||||
case Device::REBOOT_BOOTLOADER:
|
||||
ui->Print("Rebooting to bootloader...\n");
|
||||
android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
|
||||
break;
|
||||
|
||||
case Device::ENTER_FASTBOOT:
|
||||
LOG(INFO) << "Entering fastboot";
|
||||
fastboot = true;
|
||||
break;
|
||||
|
||||
case Device::ENTER_RECOVERY:
|
||||
LOG(INFO) << "Entering recovery";
|
||||
fastboot = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
ui->Print("Rebooting...\n");
|
||||
reboot("reboot,");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should be unreachable.
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+5
-18
@@ -127,13 +127,11 @@ tune2fs_static_libraries := \
|
||||
libupdater_static_libraries := \
|
||||
libupdater \
|
||||
libapplypatch \
|
||||
libbootloader_message \
|
||||
libbspatch \
|
||||
libedify \
|
||||
libziparchive \
|
||||
libotautil \
|
||||
libbootloader_message \
|
||||
libutils \
|
||||
libotafault \
|
||||
libotautil \
|
||||
libext4_utils \
|
||||
libfec \
|
||||
libfec_rs \
|
||||
@@ -144,28 +142,18 @@ libupdater_static_libraries := \
|
||||
libselinux \
|
||||
libsparse \
|
||||
libsquashfs_utils \
|
||||
libbrotli \
|
||||
libbz \
|
||||
libziparchive \
|
||||
libz \
|
||||
libbase \
|
||||
libcrypto \
|
||||
libcrypto_utils \
|
||||
libcutils \
|
||||
libutils \
|
||||
libtune2fs \
|
||||
libbrotli \
|
||||
$(tune2fs_static_libraries)
|
||||
|
||||
health_hal_static_libraries := \
|
||||
android.hardware.health@2.0-impl \
|
||||
android.hardware.health@2.0 \
|
||||
android.hardware.health@1.0 \
|
||||
android.hardware.health@1.0-convert \
|
||||
libhealthstoragedefault \
|
||||
libhidltransport \
|
||||
libhidlbase \
|
||||
libhwbinder_noltopgo \
|
||||
libvndksupport \
|
||||
libbatterymonitor
|
||||
|
||||
librecovery_static_libraries := \
|
||||
librecovery \
|
||||
libbootloader_message \
|
||||
@@ -175,7 +163,6 @@ librecovery_static_libraries := \
|
||||
libminui \
|
||||
libverifier \
|
||||
libotautil \
|
||||
$(health_hal_static_libraries) \
|
||||
libcrypto_utils \
|
||||
libcrypto \
|
||||
libext4_utils \
|
||||
|
||||
@@ -333,6 +333,25 @@ TEST(CommandsTest, Parse_ZERO) {
|
||||
ASSERT_EQ(PatchInfo(), command.patch());
|
||||
}
|
||||
|
||||
TEST(CommandsTest, Parse_COMPUTE_HASH_TREE) {
|
||||
const std::string input{ "compute_hash_tree 2,0,1 2,3,4 sha1 unknown-salt unknown-root-hash" };
|
||||
std::string err;
|
||||
Command command = Command::Parse(input, 9, &err);
|
||||
ASSERT_TRUE(command);
|
||||
|
||||
ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, command.type());
|
||||
ASSERT_EQ(9, command.index());
|
||||
ASSERT_EQ(input, command.cmdline());
|
||||
|
||||
HashTreeInfo expected_info(RangeSet({ { 0, 1 } }), RangeSet({ { 3, 4 } }), "sha1", "unknown-salt",
|
||||
"unknown-root-hash");
|
||||
ASSERT_EQ(expected_info, command.hash_tree_info());
|
||||
ASSERT_EQ(TargetInfo(), command.target());
|
||||
ASSERT_EQ(SourceInfo(), command.source());
|
||||
ASSERT_EQ(StashInfo(), command.stash());
|
||||
ASSERT_EQ(PatchInfo(), command.patch());
|
||||
}
|
||||
|
||||
TEST(CommandsTest, Parse_InvalidNumberOfArgs) {
|
||||
Command::abort_allowed_ = true;
|
||||
|
||||
@@ -341,6 +360,7 @@ TEST(CommandsTest, Parse_InvalidNumberOfArgs) {
|
||||
std::vector<std::string> inputs{
|
||||
"abort foo",
|
||||
"bsdiff",
|
||||
"compute_hash_tree, 2,0,1 2,0,1 unknown-algorithm unknown-salt",
|
||||
"erase",
|
||||
"erase 4,3,5,10,12 hash1",
|
||||
"free",
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2018 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
cc_library_static {
|
||||
name: "libupdater",
|
||||
|
||||
defaults: [
|
||||
"recovery_defaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"blockimg.cpp",
|
||||
"commands.cpp",
|
||||
"install.cpp",
|
||||
],
|
||||
|
||||
include_dirs: [
|
||||
"external/e2fsprogs/misc",
|
||||
],
|
||||
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libapplypatch",
|
||||
"libbootloader_message",
|
||||
"libbspatch",
|
||||
"libedify",
|
||||
"libotafault",
|
||||
"libotautil",
|
||||
"libext4_utils",
|
||||
"libfec",
|
||||
"libfec_rs",
|
||||
"libverity_tree",
|
||||
"libfs_mgr",
|
||||
"libgtest_prod",
|
||||
"liblog",
|
||||
"libselinux",
|
||||
"libsparse",
|
||||
"libsquashfs_utils",
|
||||
"libbrotli",
|
||||
"libbz",
|
||||
"libziparchive",
|
||||
"libz",
|
||||
"libbase",
|
||||
"libcrypto",
|
||||
"libcrypto_utils",
|
||||
"libcutils",
|
||||
"libutils",
|
||||
"libtune2fs",
|
||||
|
||||
"libext2_com_err",
|
||||
"libext2_blkid",
|
||||
"libext2_quota",
|
||||
"libext2_uuid",
|
||||
"libext2_e2p",
|
||||
"libext2fs",
|
||||
],
|
||||
}
|
||||
+4
-31
@@ -25,12 +25,10 @@ tune2fs_static_libraries := \
|
||||
updater_common_static_libraries := \
|
||||
libapplypatch \
|
||||
libbootloader_message \
|
||||
libbspatch \
|
||||
libedify \
|
||||
libotafault \
|
||||
libotautil \
|
||||
libbspatch \
|
||||
libziparchive \
|
||||
libutils \
|
||||
libext4_utils \
|
||||
libfec \
|
||||
libfec_rs \
|
||||
@@ -41,43 +39,18 @@ updater_common_static_libraries := \
|
||||
libselinux \
|
||||
libsparse \
|
||||
libsquashfs_utils \
|
||||
libbrotli \
|
||||
libbz \
|
||||
libziparchive \
|
||||
libz \
|
||||
libbase \
|
||||
libcrypto \
|
||||
libcrypto_utils \
|
||||
libcutils \
|
||||
libutils \
|
||||
libtune2fs \
|
||||
libbrotli \
|
||||
$(tune2fs_static_libraries)
|
||||
|
||||
# libupdater (static library)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libupdater
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
commands.cpp \
|
||||
install.cpp \
|
||||
blockimg.cpp
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/include \
|
||||
external/e2fsprogs/misc
|
||||
|
||||
LOCAL_CFLAGS := \
|
||||
-Wall \
|
||||
-Werror
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := \
|
||||
$(LOCAL_PATH)/include
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
$(updater_common_static_libraries)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# updater (static executable)
|
||||
# ===============================
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
+41
-1
@@ -31,6 +31,14 @@ using namespace std::string_literals;
|
||||
|
||||
bool Command::abort_allowed_ = false;
|
||||
|
||||
Command::Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info)
|
||||
: type_(type),
|
||||
index_(index),
|
||||
cmdline_(std::move(cmdline)),
|
||||
hash_tree_info_(std::move(hash_tree_info)) {
|
||||
CHECK(type == Type::COMPUTE_HASH_TREE);
|
||||
}
|
||||
|
||||
Command::Type Command::ParseType(const std::string& type_str) {
|
||||
if (type_str == "abort") {
|
||||
if (!abort_allowed_) {
|
||||
@@ -177,7 +185,6 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err)
|
||||
SourceInfo source_info;
|
||||
StashInfo stash_info;
|
||||
|
||||
// TODO(xunchang) add the parse code of compute_hash_tree
|
||||
if (op == Type::ZERO || op == Type::NEW || op == Type::ERASE) {
|
||||
// zero/new/erase <rangeset>
|
||||
if (pos + 1 != tokens.size()) {
|
||||
@@ -255,6 +262,39 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err)
|
||||
tokens.size() - pos);
|
||||
return {};
|
||||
}
|
||||
} else if (op == Type::COMPUTE_HASH_TREE) {
|
||||
// <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash>
|
||||
if (pos + 5 != tokens.size()) {
|
||||
*err = android::base::StringPrintf("invalid number of args: %zu (expected 5)",
|
||||
tokens.size() - pos);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Expects the hash_tree data to be contiguous.
|
||||
RangeSet hash_tree_ranges = RangeSet::Parse(tokens[pos++]);
|
||||
if (!hash_tree_ranges || hash_tree_ranges.size() != 1) {
|
||||
*err = "invalid hash tree ranges in: " + line;
|
||||
return {};
|
||||
}
|
||||
|
||||
RangeSet source_ranges = RangeSet::Parse(tokens[pos++]);
|
||||
if (!source_ranges) {
|
||||
*err = "invalid source ranges in: " + line;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string hash_algorithm = tokens[pos++];
|
||||
std::string salt_hex = tokens[pos++];
|
||||
std::string root_hash = tokens[pos++];
|
||||
if (hash_algorithm.empty() || salt_hex.empty() || root_hash.empty()) {
|
||||
*err = "invalid hash tree arguments in " + line;
|
||||
return {};
|
||||
}
|
||||
|
||||
HashTreeInfo hash_tree_info(std::move(hash_tree_ranges), std::move(source_ranges),
|
||||
std::move(hash_algorithm), std::move(salt_hex),
|
||||
std::move(root_hash));
|
||||
return Command(op, index, line, std::move(hash_tree_info));
|
||||
} else {
|
||||
*err = "invalid op";
|
||||
return {};
|
||||
|
||||
@@ -166,6 +166,50 @@ class PatchInfo {
|
||||
size_t length_{ 0 };
|
||||
};
|
||||
|
||||
// The arguments to build a hash tree from blocks on the block device.
|
||||
class HashTreeInfo {
|
||||
public:
|
||||
HashTreeInfo() = default;
|
||||
|
||||
HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm,
|
||||
std::string salt_hex, std::string root_hash)
|
||||
: hash_tree_ranges_(std::move(hash_tree_ranges)),
|
||||
source_ranges_(std::move(source_ranges)),
|
||||
hash_algorithm_(std::move(hash_algorithm)),
|
||||
salt_hex_(std::move(salt_hex)),
|
||||
root_hash_(std::move(root_hash)) {}
|
||||
|
||||
const RangeSet& hash_tree_ranges() const {
|
||||
return hash_tree_ranges_;
|
||||
}
|
||||
const RangeSet& source_ranges() const {
|
||||
return source_ranges_;
|
||||
}
|
||||
|
||||
const std::string& hash_algorithm() const {
|
||||
return hash_algorithm_;
|
||||
}
|
||||
const std::string& salt_hex() const {
|
||||
return salt_hex_;
|
||||
}
|
||||
const std::string& root_hash() const {
|
||||
return root_hash_;
|
||||
}
|
||||
|
||||
bool operator==(const HashTreeInfo& other) const {
|
||||
return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ &&
|
||||
hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ &&
|
||||
root_hash_ == other.root_hash_;
|
||||
}
|
||||
|
||||
private:
|
||||
RangeSet hash_tree_ranges_;
|
||||
RangeSet source_ranges_;
|
||||
std::string hash_algorithm_;
|
||||
std::string salt_hex_;
|
||||
std::string root_hash_;
|
||||
};
|
||||
|
||||
// Command class holds the info for an update command that performs block-based OTA (BBOTA). Each
|
||||
// command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo.
|
||||
// The currently used BBOTA version is v4.
|
||||
@@ -248,6 +292,8 @@ class Command {
|
||||
source_(std::move(source)),
|
||||
stash_(std::move(stash)) {}
|
||||
|
||||
Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info);
|
||||
|
||||
// Parses the given command 'line' into a Command object and returns it. The 'index' is specified
|
||||
// by the caller to index the object. On parsing error, it returns an empty Command object that
|
||||
// evaluates to false, and the specific error message will be set in 'err'.
|
||||
@@ -284,6 +330,10 @@ class Command {
|
||||
return stash_;
|
||||
}
|
||||
|
||||
const HashTreeInfo& hash_tree_info() const {
|
||||
return hash_tree_info_;
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
return type_ != Type::LAST;
|
||||
}
|
||||
@@ -325,6 +375,8 @@ class Command {
|
||||
// The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may
|
||||
// also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_).
|
||||
StashInfo stash_;
|
||||
// The hash_tree info. Only meaningful for COMPUTE_HASH_TREE.
|
||||
HashTreeInfo hash_tree_info_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Command& command);
|
||||
|
||||
Reference in New Issue
Block a user