Merge "recovery: Remove HOST_OS guard for f2fs tools"
diff --git a/Android.bp b/Android.bp
index 45aafb0..4032bcc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -58,12 +58,16 @@
],
shared_libs: [
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
"libbase",
"libbootloader_message",
"libcrypto",
"libcutils",
"libfs_mgr",
+ "liblp",
"liblog",
+ "libprotobuf-cpp-lite",
"libziparchive",
],
@@ -73,6 +77,7 @@
"libminui",
"librecovery_utils",
"libotautil",
+ "libsnapshot_nobinder",
],
}
@@ -85,7 +90,6 @@
],
srcs: [
- "fsck_unshare_blocks.cpp",
"recovery.cpp",
],
@@ -94,6 +98,14 @@
],
}
+prebuilt_etc {
+ name: "init_recovery.rc",
+ filename: "init.rc",
+ src: "etc/init.rc",
+ sub_dir: "init/hw",
+ recovery: true,
+}
+
cc_binary {
name: "recovery",
recovery: true,
@@ -119,11 +131,13 @@
required: [
"e2fsdroid.recovery",
+ "init_recovery.rc",
"librecovery_ui_ext",
"minadbd",
"mke2fs.conf.recovery",
"mke2fs.recovery",
"recovery_deps",
+ "ueventd.rc.recovery",
],
}
@@ -142,7 +156,6 @@
shared_libs: [
"libbase",
"liblog",
- "libmetricslogger",
],
static_libs: [
diff --git a/OWNERS b/OWNERS
index fe1c33d..79dd9f7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
+elsk@google.com
enh@google.com
nhdo@google.com
xunchang@google.com
diff --git a/boot_control/Android.bp b/boot_control/Android.bp
deleted file mode 100644
index b2e68df..0000000
--- a/boot_control/Android.bp
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// 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_defaults {
- name: "libboot_control_defaults",
- vendor: true,
- recovery_available: true,
- relative_install_path: "hw",
-
- cflags: [
- "-D_FILE_OFFSET_BITS=64",
- "-Werror",
- "-Wall",
- "-Wextra",
- ],
-
- shared_libs: [
- "android.hardware.boot@1.1",
- "libbase",
- "liblog",
- ],
- static_libs: [
- "libbootloader_message_vendor",
- "libfstab",
- ],
-}
-
-cc_library_static {
- name: "libboot_control",
- defaults: ["libboot_control_defaults"],
- export_include_dirs: ["include"],
-
- srcs: ["libboot_control.cpp"],
-}
-
-cc_library_shared {
- name: "bootctrl.default",
- defaults: ["libboot_control_defaults"],
-
- srcs: ["legacy_boot_control.cpp"],
-
- static_libs: [
- "libboot_control",
- ],
- shared_libs: [
- "libhardware",
- ],
-}
diff --git a/boot_control/include/libboot_control/libboot_control.h b/boot_control/include/libboot_control/libboot_control.h
deleted file mode 100644
index 34a9aff..0000000
--- a/boot_control/include/libboot_control/libboot_control.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2019 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 <android/hardware/boot/1.1/IBootControl.h>
-
-namespace android {
-namespace bootable {
-
-// Helper library to implement the IBootControl HAL using the misc partition.
-class BootControl {
- using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
-
- public:
- bool Init();
- unsigned int GetNumberSlots();
- unsigned int GetCurrentSlot();
- bool MarkBootSuccessful();
- bool SetActiveBootSlot(unsigned int slot);
- bool SetSlotAsUnbootable(unsigned int slot);
- bool SetSlotBootable(unsigned int slot);
- bool IsSlotBootable(unsigned int slot);
- const char* GetSuffix(unsigned int slot);
- bool IsSlotMarkedSuccessful(unsigned int slot);
- bool SetSnapshotMergeStatus(MergeStatus status);
- MergeStatus GetSnapshotMergeStatus();
-
- bool IsValidSlot(unsigned int slot);
-
- const std::string& misc_device() const {
- return misc_device_;
- }
-
- private:
- // Whether this object was initialized with data from the bootloader message
- // that doesn't change until next reboot.
- bool initialized_ = false;
-
- // The path to the misc_device as reported in the fstab.
- std::string misc_device_;
-
- // The number of slots present on the device.
- unsigned int num_slots_ = 0;
-
- // The slot where we are running from.
- unsigned int current_slot_ = 0;
-};
-
-} // namespace bootable
-} // namespace android
diff --git a/boot_control/legacy_boot_control.cpp b/boot_control/legacy_boot_control.cpp
deleted file mode 100644
index 73d3a58..0000000
--- a/boot_control/legacy_boot_control.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2015 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 <string>
-
-#include <hardware/boot_control.h>
-#include <hardware/hardware.h>
-
-#include <libboot_control/libboot_control.h>
-
-using android::bootable::BootControl;
-
-struct boot_control_private_t {
- // The base struct needs to be first in the list.
- boot_control_module_t base;
-
- BootControl impl;
-};
-
-namespace {
-
-void BootControl_init(boot_control_module_t* module) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- impl.Init();
-}
-
-unsigned int BootControl_getNumberSlots(boot_control_module_t* module) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.GetNumberSlots();
-}
-
-unsigned int BootControl_getCurrentSlot(boot_control_module_t* module) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.GetCurrentSlot();
-}
-
-int BootControl_markBootSuccessful(boot_control_module_t* module) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.MarkBootSuccessful() ? 0 : -1;
-}
-
-int BootControl_setActiveBootSlot(boot_control_module_t* module, unsigned int slot) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.SetActiveBootSlot(slot) ? 0 : -1;
-}
-
-int BootControl_setSlotAsUnbootable(struct boot_control_module* module, unsigned int slot) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.SetSlotAsUnbootable(slot) ? 0 : -1;
-}
-
-int BootControl_isSlotBootable(struct boot_control_module* module, unsigned int slot) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.IsSlotBootable(slot) ? 0 : -1;
-}
-
-int BootControl_isSlotMarkedSuccessful(struct boot_control_module* module, unsigned int slot) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.IsSlotMarkedSuccessful(slot) ? 0 : -1;
-}
-
-const char* BootControl_getSuffix(boot_control_module_t* module, unsigned int slot) {
- auto& impl = reinterpret_cast<boot_control_private_t*>(module)->impl;
- return impl.GetSuffix(slot);
-}
-
-static int BootControl_open(const hw_module_t* module __unused, const char* id __unused,
- hw_device_t** device __unused) {
- /* Nothing to do currently. */
- return 0;
-}
-
-struct hw_module_methods_t BootControl_methods = {
- .open = BootControl_open,
-};
-
-} // namespace
-
-boot_control_private_t HAL_MODULE_INFO_SYM = {
- .base =
- {
- .common =
- {
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
- .name = "AOSP reference bootctrl HAL",
- .author = "The Android Open Source Project",
- .methods = &BootControl_methods,
- },
- .init = BootControl_init,
- .getNumberSlots = BootControl_getNumberSlots,
- .getCurrentSlot = BootControl_getCurrentSlot,
- .markBootSuccessful = BootControl_markBootSuccessful,
- .setActiveBootSlot = BootControl_setActiveBootSlot,
- .setSlotAsUnbootable = BootControl_setSlotAsUnbootable,
- .isSlotBootable = BootControl_isSlotBootable,
- .getSuffix = BootControl_getSuffix,
- .isSlotMarkedSuccessful = BootControl_isSlotMarkedSuccessful,
- },
-};
diff --git a/boot_control/libboot_control.cpp b/boot_control/libboot_control.cpp
deleted file mode 100644
index ff4eaab..0000000
--- a/boot_control/libboot_control.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2015 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 <libboot_control/libboot_control.h>
-
-#include <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-
-#include <bootloader_message/bootloader_message.h>
-
-namespace android {
-namespace bootable {
-
-using ::android::hardware::boot::V1_1::MergeStatus;
-
-// The number of boot attempts that should be made from a new slot before
-// rolling back to the previous slot.
-constexpr unsigned int kDefaultBootAttempts = 7;
-static_assert(kDefaultBootAttempts < 8, "tries_remaining field only has 3 bits");
-
-constexpr unsigned int kMaxNumSlots =
- sizeof(bootloader_control::slot_info) / sizeof(bootloader_control::slot_info[0]);
-constexpr const char* kSlotSuffixes[kMaxNumSlots] = { "_a", "_b", "_c", "_d" };
-constexpr off_t kBootloaderControlOffset = offsetof(bootloader_message_ab, slot_suffix);
-
-static uint32_t CRC32(const uint8_t* buf, size_t size) {
- static uint32_t crc_table[256];
-
- // Compute the CRC-32 table only once.
- if (!crc_table[1]) {
- for (uint32_t i = 0; i < 256; ++i) {
- uint32_t crc = i;
- for (uint32_t j = 0; j < 8; ++j) {
- uint32_t mask = -(crc & 1);
- crc = (crc >> 1) ^ (0xEDB88320 & mask);
- }
- crc_table[i] = crc;
- }
- }
-
- uint32_t ret = -1;
- for (size_t i = 0; i < size; ++i) {
- ret = (ret >> 8) ^ crc_table[(ret ^ buf[i]) & 0xFF];
- }
-
- return ~ret;
-}
-
-// Return the little-endian representation of the CRC-32 of the first fields
-// in |boot_ctrl| up to the crc32_le field.
-uint32_t BootloaderControlLECRC(const bootloader_control* boot_ctrl) {
- return htole32(
- CRC32(reinterpret_cast<const uint8_t*>(boot_ctrl), offsetof(bootloader_control, crc32_le)));
-}
-
-bool LoadBootloaderControl(const std::string& misc_device, bootloader_control* buffer) {
- android::base::unique_fd fd(open(misc_device.c_str(), O_RDONLY));
- if (fd.get() == -1) {
- PLOG(ERROR) << "failed to open " << misc_device;
- return false;
- }
- if (lseek(fd, kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
- PLOG(ERROR) << "failed to lseek " << misc_device;
- return false;
- }
- if (!android::base::ReadFully(fd.get(), buffer, sizeof(bootloader_control))) {
- PLOG(ERROR) << "failed to read " << misc_device;
- return false;
- }
- return true;
-}
-
-bool UpdateAndSaveBootloaderControl(const std::string& misc_device, bootloader_control* buffer) {
- buffer->crc32_le = BootloaderControlLECRC(buffer);
- android::base::unique_fd fd(open(misc_device.c_str(), O_WRONLY | O_SYNC));
- if (fd.get() == -1) {
- PLOG(ERROR) << "failed to open " << misc_device;
- return false;
- }
- if (lseek(fd.get(), kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
- PLOG(ERROR) << "failed to lseek " << misc_device;
- return false;
- }
- if (!android::base::WriteFully(fd.get(), buffer, sizeof(bootloader_control))) {
- PLOG(ERROR) << "failed to write " << misc_device;
- return false;
- }
- return true;
-}
-
-void InitDefaultBootloaderControl(BootControl* control, bootloader_control* boot_ctrl) {
- memset(boot_ctrl, 0, sizeof(*boot_ctrl));
-
- unsigned int current_slot = control->GetCurrentSlot();
- if (current_slot < kMaxNumSlots) {
- strlcpy(boot_ctrl->slot_suffix, kSlotSuffixes[current_slot], sizeof(boot_ctrl->slot_suffix));
- }
- boot_ctrl->magic = BOOT_CTRL_MAGIC;
- boot_ctrl->version = BOOT_CTRL_VERSION;
-
- // Figure out the number of slots by checking if the partitions exist,
- // otherwise assume the maximum supported by the header.
- boot_ctrl->nb_slot = kMaxNumSlots;
- std::string base_path = control->misc_device();
- size_t last_path_sep = base_path.rfind('/');
- if (last_path_sep != std::string::npos) {
- // We test the existence of the "boot" partition on each possible slot,
- // which is a partition required by Android Bootloader Requirements.
- base_path = base_path.substr(0, last_path_sep + 1) + "boot";
- int last_existing_slot = -1;
- int first_missing_slot = -1;
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- std::string partition_path = base_path + kSlotSuffixes[slot];
- struct stat part_stat;
- int err = stat(partition_path.c_str(), &part_stat);
- if (!err) {
- last_existing_slot = slot;
- LOG(INFO) << "Found slot: " << kSlotSuffixes[slot];
- } else if (err < 0 && errno == ENOENT && first_missing_slot == -1) {
- first_missing_slot = slot;
- }
- }
- // We only declare that we found the actual number of slots if we found all
- // the boot partitions up to the number of slots, and no boot partition
- // after that. Not finding any of the boot partitions implies a problem so
- // we just leave the number of slots in the maximum value.
- if ((last_existing_slot != -1 && last_existing_slot + 1 == first_missing_slot) ||
- (first_missing_slot == -1 && last_existing_slot + 1 == kMaxNumSlots)) {
- boot_ctrl->nb_slot = last_existing_slot + 1;
- LOG(INFO) << "Found a system with " << last_existing_slot + 1 << " slots.";
- }
- }
-
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- slot_metadata entry = {};
-
- if (slot < boot_ctrl->nb_slot) {
- entry.priority = 7;
- entry.tries_remaining = kDefaultBootAttempts;
- entry.successful_boot = 0;
- } else {
- entry.priority = 0; // Unbootable
- }
-
- // When the boot_control stored on disk is invalid, we assume that the
- // current slot is successful. The bootloader should repair this situation
- // before booting and write a valid boot_control slot, so if we reach this
- // stage it means that the misc partition was corrupted since boot.
- if (current_slot == slot) {
- entry.successful_boot = 1;
- }
-
- boot_ctrl->slot_info[slot] = entry;
- }
- boot_ctrl->recovery_tries_remaining = 0;
-
- boot_ctrl->crc32_le = BootloaderControlLECRC(boot_ctrl);
-}
-
-// Return the index of the slot suffix passed or -1 if not a valid slot suffix.
-int SlotSuffixToIndex(const char* suffix) {
- for (unsigned int slot = 0; slot < kMaxNumSlots; ++slot) {
- if (!strcmp(kSlotSuffixes[slot], suffix)) return slot;
- }
- return -1;
-}
-
-// Initialize the boot_control_private struct with the information from
-// the bootloader_message buffer stored in |boot_ctrl|. Returns whether the
-// initialization succeeded.
-bool BootControl::Init() {
- if (initialized_) return true;
-
- // Initialize the current_slot from the read-only property. If the property
- // was not set (from either the command line or the device tree), we can later
- // initialize it from the bootloader_control struct.
- std::string suffix_prop = android::base::GetProperty("ro.boot.slot_suffix", "");
- if (suffix_prop.empty()) {
- LOG(ERROR) << "Slot suffix property is not set";
- return false;
- }
- current_slot_ = SlotSuffixToIndex(suffix_prop.c_str());
-
- std::string err;
- std::string device = get_bootloader_message_blk_device(&err);
- if (device.empty()) {
- LOG(ERROR) << "Could not find bootloader message block device: " << err;
- return false;
- }
-
- bootloader_control boot_ctrl;
- if (!LoadBootloaderControl(device.c_str(), &boot_ctrl)) {
- LOG(ERROR) << "Failed to load bootloader control block";
- return false;
- }
-
- // Note that since there isn't a module unload function this memory is leaked.
- // We use `device` below sometimes, so it's not moved out of here.
- misc_device_ = device;
- initialized_ = true;
-
- // Validate the loaded data, otherwise we will destroy it and re-initialize it
- // with the current information.
- uint32_t computed_crc32 = BootloaderControlLECRC(&boot_ctrl);
- if (boot_ctrl.crc32_le != computed_crc32) {
- LOG(WARNING) << "Invalid boot control found, expected CRC-32 0x" << std::hex << computed_crc32
- << " but found 0x" << std::hex << boot_ctrl.crc32_le << ". Re-initializing.";
- InitDefaultBootloaderControl(this, &boot_ctrl);
- UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl);
- }
-
- num_slots_ = boot_ctrl.nb_slot;
- return true;
-}
-
-unsigned int BootControl::GetNumberSlots() {
- return num_slots_;
-}
-
-unsigned int BootControl::GetCurrentSlot() {
- return current_slot_;
-}
-
-bool BootControl::MarkBootSuccessful() {
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- bootctrl.slot_info[current_slot_].successful_boot = 1;
- // tries_remaining == 0 means that the slot is not bootable anymore, make
- // sure we mark the current slot as bootable if it succeeds in the last
- // attempt.
- bootctrl.slot_info[current_slot_].tries_remaining = 1;
- return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
-}
-
-bool BootControl::SetActiveBootSlot(unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= num_slots_) {
- // Invalid slot number.
- return false;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- // Set every other slot with a lower priority than the new "active" slot.
- const unsigned int kActivePriority = 15;
- const unsigned int kActiveTries = 6;
- for (unsigned int i = 0; i < num_slots_; ++i) {
- if (i != slot) {
- if (bootctrl.slot_info[i].priority >= kActivePriority)
- bootctrl.slot_info[i].priority = kActivePriority - 1;
- }
- }
-
- // Note that setting a slot as active doesn't change the successful bit.
- // The successful bit will only be changed by setSlotAsUnbootable().
- bootctrl.slot_info[slot].priority = kActivePriority;
- bootctrl.slot_info[slot].tries_remaining = kActiveTries;
-
- // Setting the current slot as active is a way to revert the operation that
- // set *another* slot as active at the end of an updater. This is commonly
- // used to cancel the pending update. We should only reset the verity_corrpted
- // bit when attempting a new slot, otherwise the verity bit on the current
- // slot would be flip.
- if (slot != current_slot_) bootctrl.slot_info[slot].verity_corrupted = 0;
-
- return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
-}
-
-bool BootControl::SetSlotAsUnbootable(unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= num_slots_) {
- // Invalid slot number.
- return false;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- // The only way to mark a slot as unbootable, regardless of the priority is to
- // set the tries_remaining to 0.
- bootctrl.slot_info[slot].successful_boot = 0;
- bootctrl.slot_info[slot].tries_remaining = 0;
- return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
-}
-
-bool BootControl::IsSlotBootable(unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= num_slots_) {
- // Invalid slot number.
- return false;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- return bootctrl.slot_info[slot].tries_remaining != 0;
-}
-
-bool BootControl::IsSlotMarkedSuccessful(unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= num_slots_) {
- // Invalid slot number.
- return false;
- }
-
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- return bootctrl.slot_info[slot].successful_boot && bootctrl.slot_info[slot].tries_remaining;
-}
-
-bool BootControl::IsValidSlot(unsigned int slot) {
- return slot < kMaxNumSlots && slot < num_slots_;
-}
-
-bool BootControl::SetSnapshotMergeStatus(MergeStatus status) {
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
- bootctrl.merge_status = (unsigned int)status;
- return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
-}
-
-MergeStatus BootControl::GetSnapshotMergeStatus() {
- bootloader_control bootctrl;
- if (!LoadBootloaderControl(misc_device_, &bootctrl)) return MergeStatus::UNKNOWN;
-
- return (MergeStatus)bootctrl.merge_status;
-}
-
-const char* BootControl::GetSuffix(unsigned int slot) {
- if (slot >= kMaxNumSlots || slot >= num_slots_) {
- return nullptr;
- }
- return kSlotSuffixes[slot];
-}
-
-} // namespace bootable
-} // namespace android
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index b15a9b9..b70d54e 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -45,7 +45,7 @@
g_misc_device_for_test = misc_device;
}
-static std::string get_misc_blk_device(std::string* err) {
+std::string get_misc_blk_device(std::string* err) {
if (g_misc_device_for_test.has_value() && !g_misc_device_for_test->empty()) {
return *g_misc_device_for_test;
}
@@ -111,8 +111,8 @@
return true;
}
-static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
- size_t offset, std::string* err) {
+bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err) {
android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
if (fd == -1) {
*err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
@@ -250,41 +250,60 @@
if (misc_blk_device.empty()) {
return false;
}
+ static constexpr size_t kMaximumWipePackageSize =
+ SYSTEM_SPACE_OFFSET_IN_MISC - WIPE_PACKAGE_OFFSET_IN_MISC;
+ if (package_data.size() > kMaximumWipePackageSize) {
+ *err = "Wipe package size " + std::to_string(package_data.size()) + " exceeds " +
+ std::to_string(kMaximumWipePackageSize) + " bytes";
+ return false;
+ }
return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device,
WIPE_PACKAGE_OFFSET_IN_MISC, err);
}
-static bool OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
- auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
- return size <= total_size && offset <= total_size - size;
+static bool ValidateSystemSpaceRegion(size_t offset, size_t size, std::string* err) {
+ if (size <= SYSTEM_SPACE_SIZE_IN_MISC && offset <= (SYSTEM_SPACE_SIZE_IN_MISC - size)) {
+ return true;
+ }
+ *err = android::base::StringPrintf("Out of bound access (offset %zu size %zu)", offset, size);
+ return false;
}
-bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err) {
- if (!OffsetAndSizeInVendorSpace(offset, size)) {
- *err = android::base::StringPrintf("Out of bound read (offset %zu size %zu)", offset, size);
+static bool ReadMiscPartitionSystemSpace(void* data, size_t size, size_t offset, std::string* err) {
+ if (!ValidateSystemSpaceRegion(offset, size, err)) {
return false;
}
auto misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
- return read_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
+ return read_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
err);
}
-bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err) {
- if (!OffsetAndSizeInVendorSpace(offset, size)) {
- *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
+static bool WriteMiscPartitionSystemSpace(const void* data, size_t size, size_t offset,
+ std::string* err) {
+ if (!ValidateSystemSpaceRegion(offset, size, err)) {
return false;
}
auto misc_blk_device = get_misc_blk_device(err);
if (misc_blk_device.empty()) {
return false;
}
- return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
+ return write_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
err);
}
+bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err) {
+ return ReadMiscPartitionSystemSpace(message, sizeof(*message),
+ offsetof(misc_system_space_layout, virtual_ab_message), err);
+}
+
+bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err) {
+ return WriteMiscPartitionSystemSpace(&message, sizeof(message),
+ offsetof(misc_system_space_layout, virtual_ab_message), err);
+}
+
extern "C" bool write_reboot_bootloader(void) {
std::string err;
return write_reboot_bootloader(&err);
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index b787830..e4cf09b 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -25,12 +25,15 @@
// 0 - 2K For bootloader_message
// 2K - 16K Used by Vendor's bootloader (the 2K - 4K range may be optionally used
// as bootloader_message_ab struct)
-// 16K - 64K Used by uncrypt and recovery to store wipe_package for A/B devices
+// 16K - 32K Used by uncrypt and recovery to store wipe_package for A/B devices
+// 32K - 64K System space, used for miscellanious AOSP features. See below.
// Note that these offsets are admitted by bootloader,recovery and uncrypt, so they
// are not configurable without changing all of them.
constexpr size_t BOOTLOADER_MESSAGE_OFFSET_IN_MISC = 0;
constexpr size_t VENDOR_SPACE_OFFSET_IN_MISC = 2 * 1024;
constexpr size_t WIPE_PACKAGE_OFFSET_IN_MISC = 16 * 1024;
+constexpr size_t SYSTEM_SPACE_OFFSET_IN_MISC = 32 * 1024;
+constexpr size_t SYSTEM_SPACE_SIZE_IN_MISC = 32 * 1024;
/* Bootloader Message (2-KiB)
*
@@ -80,118 +83,47 @@
char reserved[1184];
};
-/**
- * We must be cautious when changing the bootloader_message struct size,
- * because A/B-specific fields may end up with different offsets.
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message) == 2048,
- "struct bootloader_message size changes, which may break A/B devices");
-#endif
-
-/**
- * The A/B-specific bootloader message structure (4-KiB).
- *
- * We separate A/B boot control metadata from the regular bootloader
- * message struct and keep it here. Everything that's A/B-specific
- * stays after struct bootloader_message, which should be managed by
- * the A/B-bootloader or boot control HAL.
- *
- * The slot_suffix field is used for A/B implementations where the
- * bootloader does not set the androidboot.ro.boot.slot_suffix kernel
- * commandline parameter. This is used by fs_mgr to mount /system and
- * other partitions with the slotselect flag set in fstab. A/B
- * implementations are free to use all 32 bytes and may store private
- * data past the first NUL-byte in this field. It is encouraged, but
- * not mandatory, to use 'struct bootloader_control' described below.
- *
- * The update_channel field is used to store the Omaha update channel
- * if update_engine is compiled with Omaha support.
- */
-struct bootloader_message_ab {
- struct bootloader_message message;
- char slot_suffix[32];
- char update_channel[128];
-
- // Round up the entire struct to 4096-byte.
- char reserved[1888];
-};
-
-/**
- * Be cautious about the struct size change, in case we put anything post
- * bootloader_message_ab struct (b/29159185).
- */
-#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_message_ab) == 4096,
- "struct bootloader_message_ab size changes");
-#endif
-
-#define BOOT_CTRL_MAGIC 0x42414342 /* Bootloader Control AB */
-#define BOOT_CTRL_VERSION 1
-
-struct slot_metadata {
- // Slot priority with 15 meaning highest priority, 1 lowest
- // priority and 0 the slot is unbootable.
- uint8_t priority : 4;
- // Number of times left attempting to boot this slot.
- uint8_t tries_remaining : 3;
- // 1 if this slot has booted successfully, 0 otherwise.
- uint8_t successful_boot : 1;
- // 1 if this slot is corrupted from a dm-verity corruption, 0
- // otherwise.
- uint8_t verity_corrupted : 1;
- // Reserved for further use.
- uint8_t reserved : 7;
+// Holds Virtual A/B merge status information. Current version is 1. New fields
+// must be added to the end.
+struct misc_virtual_ab_message {
+ uint8_t version;
+ uint32_t magic;
+ uint8_t merge_status; // IBootControl 1.1, MergeStatus enum.
+ uint8_t source_slot; // Slot number when merge_status was written.
+ uint8_t reserved[57];
} __attribute__((packed));
-/* Bootloader Control AB
- *
- * This struct can be used to manage A/B metadata. It is designed to
- * be put in the 'slot_suffix' field of the 'bootloader_message'
- * structure described above. It is encouraged to use the
- * 'bootloader_control' structure to store the A/B metadata, but not
- * mandatory.
- */
-struct bootloader_control {
- // NUL terminated active slot suffix.
- char slot_suffix[4];
- // Bootloader Control AB magic number (see BOOT_CTRL_MAGIC).
- uint32_t magic;
- // Version of struct being used (see BOOT_CTRL_VERSION).
- uint8_t version;
- // Number of slots being managed.
- uint8_t nb_slot : 3;
- // Number of times left attempting to boot recovery.
- uint8_t recovery_tries_remaining : 3;
- // Status of any pending snapshot merge of dynamic partitions.
- uint8_t merge_status : 3;
- // Ensure 4-bytes alignment for slot_info field.
- uint8_t reserved0[1];
- // Per-slot information. Up to 4 slots.
- struct slot_metadata slot_info[4];
- // Reserved for further use.
- uint8_t reserved1[8];
- // CRC32 of all 28 bytes preceding this field (little endian
- // format).
- uint32_t crc32_le;
-} __attribute__((packed));
+#define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
+#define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
-static_assert(sizeof(struct bootloader_control) ==
- sizeof(((struct bootloader_message_ab *)0)->slot_suffix),
- "struct bootloader_control has wrong size");
+static_assert(sizeof(struct misc_virtual_ab_message) == 64,
+ "struct misc_virtual_ab_message has wrong size");
#endif
+// This struct is not meant to be used directly, rather, it is to make
+// computation of offsets easier. New fields must be added to the end.
+struct misc_system_space_layout {
+ misc_virtual_ab_message virtual_ab_message;
+} __attribute__((packed));
+
#ifdef __cplusplus
#include <string>
#include <vector>
+// Gets the block device name of /misc partition.
+std::string get_misc_blk_device(std::string* err);
// Return the block device name for the bootloader message partition and waits
// for the device for up to 10 seconds. In case of error returns the empty
// string.
std::string get_bootloader_message_blk_device(std::string* err);
+// Writes |size| bytes of data from buffer |p| to |misc_blk_device| at |offset|. If the write fails,
+// sets the error message in |err|.
+bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
+ size_t offset, std::string* err);
+
// Read bootloader message into boot. Error message will be set in err.
bool read_bootloader_message(bootloader_message* boot, std::string* err);
@@ -236,13 +168,9 @@
// Write the wipe package into BCB (to offset WIPE_PACKAGE_OFFSET_IN_MISC).
bool write_wipe_package(const std::string& package_data, std::string* err);
-// Reads data from the vendor space in /misc partition, with the given offset and size. Note that
-// offset is in relative to the start of vendor space.
-bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err);
-
-// Writes the given data to the vendor space in /misc partition, at the given offset. Note that
-// offset is in relative to the start of the vendor space.
-bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err);
+// Read or write the Virtual A/B message from system space in /misc.
+bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
+bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);
#else
diff --git a/edify/Android.bp b/edify/Android.bp
index 73048d2..0ab53d6 100644
--- a/edify/Android.bp
+++ b/edify/Android.bp
@@ -17,6 +17,7 @@
host_supported: true,
vendor_available: true,
+ recovery_available: true,
srcs: [
"expr.cpp",
diff --git a/edify/parser.yy b/edify/parser.yy
index 3a63c37..37bcdd0 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -72,7 +72,7 @@
%parse-param {std::unique_ptr<Expr>* root}
%parse-param {int* error_count}
-%error-verbose
+%define parse.error verbose
/* declarations in increasing order of precedence */
%left ';'
diff --git a/etc/init.rc b/etc/init.rc
index 0822aba..3ec45db 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -4,6 +4,10 @@
# Set the security context of /postinstall if present.
restorecon /postinstall
+ # Copy prebuilt ld.config.txt into linkerconfig directory
+ copy /system/etc/ld.config.txt /linkerconfig/ld.config.txt
+ chmod 444 /linkerconfig/ld.config.txt
+
start ueventd
setprop sys.usb.configfs 0
@@ -44,10 +48,6 @@
class_start default
-# Load properties from /system/ + /factory after fs mount.
-on load_system_props_action
- load_system_props
-
on firmware_mounts_complete
rm /dev/.booting
@@ -58,11 +58,6 @@
trigger post-fs
trigger post-fs-data
- # Load properties from /system/ + /factory after fs mount. Place
- # this in another action so that the load will be scheduled after the prior
- # issued fs triggers have completed.
- trigger load_system_props_action
-
# Remove a file to wake up anything waiting for firmware
trigger firmware_mounts_complete
@@ -95,10 +90,6 @@
on property:service.adb.root=1
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
@@ -134,7 +125,7 @@
on property:sys.usb.config=none && property:sys.usb.configfs=0
stop adbd
- stop fastboot
+ stop fastbootd
write /sys/class/android_usb/android0/enable 0
setprop sys.usb.state ${sys.usb.config}
diff --git a/fsck_unshare_blocks.cpp b/fsck_unshare_blocks.cpp
deleted file mode 100644
index e0b2d96..0000000
--- a/fsck_unshare_blocks.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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 "fsck_unshare_blocks.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <spawn.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr/roots.h>
-
-#include "recovery_utils/roots.h"
-
-static constexpr const char* SYSTEM_E2FSCK_BIN = "/system/bin/e2fsck_static";
-static constexpr const char* TMP_E2FSCK_BIN = "/tmp/e2fsck.bin";
-
-static bool copy_file(const char* source, const char* dest) {
- android::base::unique_fd source_fd(open(source, O_RDONLY));
- if (source_fd < 0) {
- PLOG(ERROR) << "open %s failed" << source;
- return false;
- }
-
- android::base::unique_fd dest_fd(open(dest, O_CREAT | O_WRONLY, S_IRWXU));
- if (dest_fd < 0) {
- PLOG(ERROR) << "open %s failed" << dest;
- return false;
- }
-
- for (;;) {
- char buf[4096];
- ssize_t rv = read(source_fd, buf, sizeof(buf));
- if (rv < 0) {
- PLOG(ERROR) << "read failed";
- return false;
- }
- if (rv == 0) {
- break;
- }
- if (write(dest_fd, buf, rv) != rv) {
- PLOG(ERROR) << "write failed";
- return false;
- }
- }
- return true;
-}
-
-static bool run_e2fsck(const std::string& partition) {
- Volume* volume = volume_for_mount_point(partition);
- if (!volume) {
- LOG(INFO) << "No fstab entry for " << partition << ", skipping.";
- return true;
- }
-
- LOG(INFO) << "Running e2fsck on device " << volume->blk_device;
-
- std::vector<std::string> args = { TMP_E2FSCK_BIN, "-p", "-E", "unshare_blocks",
- volume->blk_device };
- std::vector<char*> argv(args.size());
- std::transform(args.cbegin(), args.cend(), argv.begin(),
- [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
- argv.push_back(nullptr);
-
- pid_t child;
- char* env[] = { nullptr };
- if (posix_spawn(&child, argv[0], nullptr, nullptr, argv.data(), env)) {
- PLOG(ERROR) << "posix_spawn failed";
- return false;
- }
-
- int status = 0;
- int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
- if (ret < 0) {
- PLOG(ERROR) << "waitpid failed";
- return false;
- }
- if (!WIFEXITED(status)) {
- LOG(ERROR) << "e2fsck exited abnormally: " << status;
- return false;
- }
- int return_code = WEXITSTATUS(status);
- if (return_code >= 8) {
- LOG(ERROR) << "e2fsck could not unshare blocks: " << return_code;
- return false;
- }
-
- LOG(INFO) << "Successfully unshared blocks on " << partition;
- return true;
-}
-
-bool do_fsck_unshare_blocks() {
- // List of partitions we will try to e2fsck -E unshare_blocks.
- std::vector<std::string> partitions = { "/odm", "/oem", "/product", "/vendor" };
-
- // Temporarily mount system so we can copy e2fsck_static.
- auto system_root = android::fs_mgr::GetSystemRoot();
- bool mounted = ensure_path_mounted_at(system_root, "/mnt/system") != -1;
- partitions.push_back(system_root);
-
- if (!mounted) {
- LOG(ERROR) << "Failed to mount system image.";
- return false;
- }
- if (!copy_file(SYSTEM_E2FSCK_BIN, TMP_E2FSCK_BIN)) {
- LOG(ERROR) << "Could not copy e2fsck to /tmp.";
- return false;
- }
- if (umount("/mnt/system") < 0) {
- PLOG(ERROR) << "umount failed";
- return false;
- }
-
- bool ok = true;
- for (const auto& partition : partitions) {
- ok &= run_e2fsck(partition);
- }
-
- if (ok) {
- LOG(INFO) << "Finished running e2fsck.";
- } else {
- LOG(ERROR) << "Finished running e2fsck, but not all partitions succceeded.";
- }
- return ok;
-}
diff --git a/fsck_unshare_blocks.h b/fsck_unshare_blocks.h
deleted file mode 100644
index 9de8ef9..0000000
--- a/fsck_unshare_blocks.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _FILESYSTEM_CMDS_H
-#define _FILESYSTEM_CMDS_H
-
-bool do_fsck_unshare_blocks();
-
-#endif // _FILESYSTEM_CMDS_H
diff --git a/install/Android.bp b/install/Android.bp
index d4606e9..bed3bc5 100644
--- a/install/Android.bp
+++ b/install/Android.bp
@@ -39,9 +39,9 @@
static_libs: [
"librecovery_utils",
"libotautil",
+ "libsnapshot_nobinder",
// external dependencies
- "libvintf_recovery",
"libvintf",
],
}
@@ -60,6 +60,7 @@
"fuse_install.cpp",
"install.cpp",
"package.cpp",
+ "snapshot_utils.cpp",
"verifier.cpp",
"wipe_data.cpp",
"wipe_device.cpp",
diff --git a/install/include/install/install.h b/install/include/install/install.h
index b4b3a91..87d43ab 100644
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -59,10 +59,6 @@
// result to |metadata|. Return true if succeed, otherwise return false.
bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata);
-// Verifies the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist.
-bool verify_package_compatibility(ZipArchiveHandle package_zip);
-
// Checks if the metadata in the OTA package has expected values. Mandatory checks: ota-type,
// pre-device and serial number (if presents). A/B OTA specific checks: pre-build version,
// fingerprint, timestamp.
diff --git a/install/include/install/snapshot_utils.h b/install/include/install/snapshot_utils.h
new file mode 100644
index 0000000..f4b978d
--- /dev/null
+++ b/install/include/install/snapshot_utils.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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 "recovery_ui/device.h"
+
+bool FinishPendingSnapshotMerges(Device* device);
+
+/*
+ * This function tries to create the snapshotted devices in the case a Virtual
+ * A/B device is updating.
+ * The function returns false in case of critical failure that would prevent
+ * the further mountings of devices, or true in case of success, if either the
+ * devices were created or there was no need to.
+ */
+bool CreateSnapshotPartitions();
diff --git a/install/install.cpp b/install/install.cpp
index 9166f9c..4bb0903 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -44,7 +44,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <vintf/VintfObjectRecovery.h>
#include "install/package.h"
#include "install/verifier.h"
@@ -505,73 +504,6 @@
return INSTALL_SUCCESS;
}
-// Verifies the compatibility info in a Treble-compatible package. Returns true directly if the
-// entry doesn't exist. Note that the compatibility info is packed in a zip file inside the OTA
-// package.
-bool verify_package_compatibility(ZipArchiveHandle package_zip) {
- LOG(INFO) << "Verifying package compatibility...";
-
- static constexpr const char* COMPATIBILITY_ZIP_ENTRY = "compatibility.zip";
- ZipEntry compatibility_entry;
- if (FindEntry(package_zip, COMPATIBILITY_ZIP_ENTRY, &compatibility_entry) != 0) {
- LOG(INFO) << "Package doesn't contain " << COMPATIBILITY_ZIP_ENTRY << " entry";
- return true;
- }
-
- std::string zip_content(compatibility_entry.uncompressed_length, '\0');
- int32_t ret;
- if ((ret = ExtractToMemory(package_zip, &compatibility_entry,
- reinterpret_cast<uint8_t*>(&zip_content[0]),
- compatibility_entry.uncompressed_length)) != 0) {
- LOG(ERROR) << "Failed to read " << COMPATIBILITY_ZIP_ENTRY << ": " << ErrorCodeString(ret);
- return false;
- }
-
- ZipArchiveHandle zip_handle;
- ret = OpenArchiveFromMemory(static_cast<void*>(const_cast<char*>(zip_content.data())),
- zip_content.size(), COMPATIBILITY_ZIP_ENTRY, &zip_handle);
- if (ret != 0) {
- LOG(ERROR) << "Failed to OpenArchiveFromMemory: " << ErrorCodeString(ret);
- return false;
- }
-
- // Iterate all the entries inside COMPATIBILITY_ZIP_ENTRY and read the contents.
- void* cookie;
- ret = StartIteration(zip_handle, &cookie);
- if (ret != 0) {
- LOG(ERROR) << "Failed to start iterating zip entries: " << ErrorCodeString(ret);
- CloseArchive(zip_handle);
- return false;
- }
- std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
-
- std::vector<std::string> compatibility_info;
- ZipEntry info_entry;
- std::string_view info_name;
- while (Next(cookie, &info_entry, &info_name) == 0) {
- std::string content(info_entry.uncompressed_length, '\0');
- int32_t ret = ExtractToMemory(zip_handle, &info_entry, reinterpret_cast<uint8_t*>(&content[0]),
- info_entry.uncompressed_length);
- if (ret != 0) {
- LOG(ERROR) << "Failed to read " << info_name << ": " << ErrorCodeString(ret);
- CloseArchive(zip_handle);
- return false;
- }
- compatibility_info.emplace_back(std::move(content));
- }
- CloseArchive(zip_handle);
-
- // VintfObjectRecovery::CheckCompatibility returns zero on success.
- std::string err;
- int result = android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err);
- if (result == 0) {
- return true;
- }
-
- LOG(ERROR) << "Failed to verify package compatibility (result " << result << "): " << err;
- return false;
-}
-
static InstallResult VerifyAndInstallPackage(Package* package, bool* wipe_cache,
std::vector<std::string>* log_buffer, int retry_count,
int* max_temperature, RecoveryUI* ui) {
@@ -586,19 +518,6 @@
return INSTALL_CORRUPT;
}
- // Try to open the package.
- ZipArchiveHandle zip = package->GetZipArchiveHandle();
- if (!zip) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
- return INSTALL_CORRUPT;
- }
-
- // Additionally verify the compatibility of the package if it's a fresh install.
- if (retry_count == 0 && !verify_package_compatibility(zip)) {
- log_buffer->push_back(android::base::StringPrintf("error: %d", kPackageCompatibilityFailure));
- return INSTALL_CORRUPT;
- }
-
// Verify and install the contents of the package.
ui->Print("Installing update...\n");
if (retry_count > 0) {
diff --git a/install/snapshot_utils.cpp b/install/snapshot_utils.cpp
new file mode 100644
index 0000000..7235e67
--- /dev/null
+++ b/install/snapshot_utils.cpp
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright (C) 2019 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 <android-base/logging.h>
+#include <android-base/properties.h>
+#include <libsnapshot/snapshot.h>
+
+#include "recovery_ui/device.h"
+#include "recovery_ui/ui.h"
+#include "recovery_utils/roots.h"
+
+using android::snapshot::CreateResult;
+using android::snapshot::SnapshotManager;
+
+bool FinishPendingSnapshotMerges(Device* device) {
+ if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ return true;
+ }
+
+ RecoveryUI* ui = device->GetUI();
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ ui->Print("Could not create SnapshotManager.\n");
+ return false;
+ }
+
+ auto callback = [&]() -> void {
+ double progress;
+ sm->GetUpdateState(&progress);
+ ui->Print("Waiting for merge to complete: %.2f\n", progress);
+ };
+ if (!sm->HandleImminentDataWipe(callback)) {
+ ui->Print("Unable to check merge status and/or complete update merge.\n");
+ return false;
+ }
+ return true;
+}
+
+bool CreateSnapshotPartitions() {
+ if (!android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
+ // If the device does not support Virtual A/B, there's no need to create
+ // snapshot devices.
+ return true;
+ }
+
+ auto sm = SnapshotManager::NewForFirstStageMount();
+ if (!sm) {
+ // SnapshotManager could not be created. The device is still in a
+ // consistent state and can continue with the mounting of the existing
+ // devices, but cannot initialize snapshot devices.
+ LOG(WARNING) << "Could not create SnapshotManager";
+ return true;
+ }
+
+ auto ret = sm->RecoveryCreateSnapshotDevices();
+ if (ret == CreateResult::ERROR) {
+ return false;
+ }
+ return true;
+}
diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp
index 82660be..2872085 100644
--- a/install/wipe_data.cpp
+++ b/install/wipe_data.cpp
@@ -27,6 +27,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "install/snapshot_utils.h"
#include "otautil/dirutil.h"
#include "recovery_ui/ui.h"
#include "recovery_utils/logging.h"
@@ -104,6 +105,12 @@
bool WipeData(Device* device, bool convert_fbe) {
RecoveryUI* ui = device->GetUI();
ui->Print("\n-- Wiping data...\n");
+
+ if (!FinishPendingSnapshotMerges(device)) {
+ ui->Print("Unable to check update status or complete merge, cannot wipe partitions.\n");
+ return false;
+ }
+
bool success = device->PreWipeData();
if (success) {
success &= EraseVolume(DATA_ROOT, ui, convert_fbe);
diff --git a/minui/events.cpp b/minui/events.cpp
index f331ed6..87f8112 100644
--- a/minui/events.cpp
+++ b/minui/events.cpp
@@ -90,9 +90,11 @@
// The inotify will put one or several complete events.
// Should not read part of one event.
- size_t event_len;
- int ret = ioctl(fd, FIONREAD, &event_len);
+ int event_len_int;
+ int ret = ioctl(fd, FIONREAD, &event_len_int);
if (ret != 0) return -1;
+ if (event_len_int < 0) return -1;
+ size_t event_len = event_len_int;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir);
if (!dir) {
diff --git a/minui/graphics.cpp b/minui/graphics.cpp
index 4d1f9b2..d34da56 100644
--- a/minui/graphics.cpp
+++ b/minui/graphics.cpp
@@ -209,7 +209,7 @@
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
uint32_t r32 = r, g32 = g, b32 = b, a32 = a;
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32;
} else {
gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32;
@@ -348,6 +348,8 @@
pixel_format = PixelFormat::ABGR;
} else if (format == "RGBX_8888") {
pixel_format = PixelFormat::RGBX;
+ } else if (format == "ARGB_8888") {
+ pixel_format = PixelFormat::ARGB;
} else if (format == "BGRA_8888") {
pixel_format = PixelFormat::BGRA;
} else {
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp
index 7b2eed1..95759e3 100644
--- a/minui/graphics_drm.cpp
+++ b/minui/graphics_drm.cpp
@@ -62,6 +62,8 @@
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_XRGB8888:
@@ -87,6 +89,8 @@
format = DRM_FORMAT_ARGB8888;
} else if (pixel_format == PixelFormat::RGBX) {
format = DRM_FORMAT_XBGR8888;
+ } else if (pixel_format == PixelFormat::ARGB) {
+ format = DRM_FORMAT_BGRA8888;
} else {
format = DRM_FORMAT_RGB565;
}
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 36bdcf1..163e41d 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -101,6 +101,7 @@
ABGR = 1,
RGBX = 2,
BGRA = 3,
+ ARGB = 4,
};
// Initializes the graphics backend and loads font file. Returns 0 on success, or -1 on error. Note
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 00d36d5..f635acd 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -199,7 +199,7 @@
}
PixelFormat pixel_format = gr_pixel_format();
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
@@ -271,7 +271,7 @@
surface[i] = created_surface.release();
}
- if (gr_pixel_format() == PixelFormat::ABGR || gr_pixel_format() == PixelFormat::BGRA) {
+ if (gr_pixel_format() == PixelFormat::ARGB || gr_pixel_format() == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
@@ -317,7 +317,7 @@
}
PixelFormat pixel_format = gr_pixel_format();
- if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) {
+ if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) {
png_set_bgr(png_ptr);
}
diff --git a/misc_writer/Android.bp b/misc_writer/Android.bp
deleted file mode 100644
index 567143c..0000000
--- a/misc_writer/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright (C) 2019 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_binary {
- name: "misc_writer",
- vendor: true,
-
- srcs: [
- "misc_writer.cpp",
- ],
-
- cpp_std: "experimental",
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- shared_libs: [
- "libbase",
- ],
-
- static_libs: [
- "libbootloader_message_vendor",
- "libfstab",
- ],
-}
diff --git a/misc_writer/misc_writer.cpp b/misc_writer/misc_writer.cpp
deleted file mode 100644
index 1d9702e..0000000
--- a/misc_writer/misc_writer.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2019 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 <errno.h>
-#include <getopt.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <iostream>
-#include <string>
-#include <string_view>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <bootloader_message/bootloader_message.h>
-
-using namespace std::string_literals;
-
-static std::vector<uint8_t> ParseHexString(std::string_view hex_string) {
- auto length = hex_string.size();
- if (length % 2 != 0 || length == 0) {
- return {};
- }
-
- std::vector<uint8_t> result(length / 2);
- for (size_t i = 0; i < length / 2; i++) {
- auto sub = "0x" + std::string(hex_string.substr(i * 2, 2));
- if (!android::base::ParseUint(sub, &result[i])) {
- return {};
- }
- }
- return result;
-}
-
-static int Usage(std::string_view name) {
- std::cerr << name << " usage:\n";
- std::cerr << name << " [--vendor-space-offset <offset>] --hex-string 0xABCDEF\n";
- std::cerr << "Writes the given hex string to the specified offset in vendor space in /misc "
- "partition. Offset defaults to 0 if unspecified.\n";
- return EXIT_FAILURE;
-}
-
-// misc_writer is a vendor tool that writes data to the vendor space in /misc.
-int main(int argc, char** argv) {
- constexpr struct option OPTIONS[] = {
- { "vendor-space-offset", required_argument, nullptr, 0 },
- { "hex-string", required_argument, nullptr, 0 },
- { nullptr, 0, nullptr, 0 },
- };
-
- // Offset defaults to 0 if unspecified.
- size_t offset = 0;
- std::string_view hex_string;
-
- int arg;
- int option_index;
- while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) {
- if (arg != 0) {
- LOG(ERROR) << "Invalid command argument";
- return Usage(argv[0]);
- }
- auto option_name = OPTIONS[option_index].name;
- if (option_name == "vendor-space-offset"s) {
- if (!android::base::ParseUint(optarg, &offset)) {
- LOG(ERROR) << "Failed to parse the offset: " << optarg;
- return Usage(argv[0]);
- }
- } else if (option_name == "hex-string"s) {
- hex_string = optarg;
- }
- }
-
- if (hex_string.starts_with("0x") || hex_string.starts_with("0X")) {
- hex_string = hex_string.substr(2);
- }
- if (hex_string.empty()) {
- LOG(ERROR) << "Invalid input hex string: " << hex_string;
- return Usage(argv[0]);
- }
-
- auto data = ParseHexString(hex_string);
- if (data.empty()) {
- LOG(ERROR) << "Failed to parse the input hex string: " << hex_string;
- return EXIT_FAILURE;
- }
- if (std::string err; !WriteMiscPartitionVendorSpace(data.data(), data.size(), offset, &err)) {
- LOG(ERROR) << "Failed to write to misc partition: " << err;
- return EXIT_FAILURE;
- }
- return EXIT_SUCCESS;
-}
diff --git a/recovery-persist.cpp b/recovery-persist.cpp
index 6dbf862..ad101ed 100644
--- a/recovery-persist.cpp
+++ b/recovery-persist.cpp
@@ -35,12 +35,10 @@
#include <string.h>
#include <unistd.h>
-#include <limits>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <metricslogger/metrics_logger.h>
#include <private/android_logger.h> /* private pmsg functions */
#include "recovery_utils/logging.h"
@@ -112,20 +110,6 @@
return android::base::WriteStringToFile(buffer, destination.c_str());
}
-// Parses the LAST_INSTALL file and reports the update metrics saved under recovery mode.
-static void report_metrics_from_last_install(const std::string& file_name) {
- auto metrics = ParseLastInstall(file_name);
- // TODO(xunchang) report the installation result.
- for (const auto& [event, value] : metrics) {
- if (value > std::numeric_limits<int>::max()) {
- LOG(WARNING) << event << " (" << value << ") exceeds integer max.";
- } else {
- LOG(INFO) << "Uploading " << value << " to " << event;
- android::metricslogger::LogHistogram(event, value);
- }
- }
-}
-
int main(int argc, char **argv) {
/* Is /cache a mount?, we have been delivered where we are not wanted */
@@ -157,7 +141,6 @@
if (has_cache) {
// Collects and reports the non-a/b update metrics from last_install; and removes the file
// to avoid duplicate report.
- report_metrics_from_last_install(LAST_INSTALL_FILE_IN_CACHE);
if (access(LAST_INSTALL_FILE_IN_CACHE, F_OK) && unlink(LAST_INSTALL_FILE_IN_CACHE) == -1) {
PLOG(ERROR) << "Failed to unlink " << LAST_INSTALL_FILE_IN_CACHE;
}
@@ -181,7 +164,6 @@
// For those device without /cache, the last_install file has been copied to
// /data/misc/recovery from pmsg. Looks for the sideload history only.
if (!has_cache) {
- report_metrics_from_last_install(LAST_INSTALL_FILE);
if (access(LAST_INSTALL_FILE, F_OK) && unlink(LAST_INSTALL_FILE) == -1) {
PLOG(ERROR) << "Failed to unlink " << LAST_INSTALL_FILE;
}
diff --git a/recovery.cpp b/recovery.cpp
index f59a940..9ea616e 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -45,11 +45,11 @@
#include <ziparchive/zip_archive.h>
#include "bootloader_message/bootloader_message.h"
-#include "fsck_unshare_blocks.h"
#include "install/adb_install.h"
#include "install/fuse_install.h"
#include "install/install.h"
#include "install/package.h"
+#include "install/snapshot_utils.h"
#include "install/wipe_data.h"
#include "install/wipe_device.h"
#include "otautil/boot_state.h"
@@ -310,11 +310,56 @@
ui->ShowText(true);
}
+static void WriteUpdateInProgress() {
+ std::string err;
+ if (!update_bootloader_message({ "--reason=update_in_progress" }, &err)) {
+ LOG(ERROR) << "Failed to WriteUpdateInProgress: " << err;
+ }
+}
+
+static bool AskToReboot(Device* device, Device::BuiltinAction chosen_action) {
+ bool is_non_ab = android::base::GetProperty("ro.boot.slot_suffix", "").empty();
+ bool is_virtual_ab = android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+ if (!is_non_ab && !is_virtual_ab) {
+ // Only prompt for non-A/B or Virtual A/B devices.
+ return true;
+ }
+
+ std::string header_text;
+ std::string item_text;
+ switch (chosen_action) {
+ case Device::REBOOT:
+ header_text = "reboot";
+ item_text = " Reboot system now";
+ break;
+ case Device::SHUTDOWN:
+ header_text = "power off";
+ item_text = " Power off";
+ break;
+ default:
+ LOG(FATAL) << "Invalid chosen action " << chosen_action;
+ break;
+ }
+
+ std::vector<std::string> headers{ "WARNING: Previous installation has failed.",
+ " Your device may fail to boot if you " + header_text +
+ " now.",
+ " Confirm reboot?" };
+ std::vector<std::string> items{ " Cancel", item_text };
+
+ size_t chosen_item = device->GetUI()->ShowMenu(
+ headers, items, 0, true /* menu_only */,
+ std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
+
+ return (chosen_item == 1);
+}
+
// Shows the recovery UI and waits for user input. Returns one of the device builtin actions, such
// as REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION means to take the default, which
// is to reboot or shutdown depending on if the --shutdown_after flag was passed to recovery.
static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status) {
auto ui = device->GetUI();
+ bool update_in_progress = (device->GetReason().value_or("") == "update_in_progress");
for (;;) {
FinishRecovery(ui);
switch (status) {
@@ -339,8 +384,14 @@
}
ui->SetProgressType(RecoveryUI::EMPTY);
+ std::vector<std::string> headers;
+ if (update_in_progress) {
+ headers = { "WARNING: Previous installation has failed.",
+ " Your device may fail to boot if you reboot or power off now." };
+ }
+
size_t chosen_item = ui->ShowMenu(
- {}, device->GetMenuItems(), 0, false,
+ headers, device->GetMenuItems(), 0, false,
std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
// Handle Interrupt key
if (chosen_item == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
@@ -361,14 +412,27 @@
case Device::ENTER_FASTBOOT:
case Device::ENTER_RECOVERY:
- case Device::REBOOT:
case Device::REBOOT_BOOTLOADER:
case Device::REBOOT_FASTBOOT:
case Device::REBOOT_RECOVERY:
case Device::REBOOT_RESCUE:
- case Device::SHUTDOWN:
return chosen_action;
+ case Device::REBOOT:
+ case Device::SHUTDOWN:
+ if (!ui->IsTextVisible()) {
+ return Device::REBOOT;
+ }
+ // okay to reboot; no need to ask.
+ if (!update_in_progress) {
+ return Device::REBOOT;
+ }
+ // An update might have been failed. Ask if user really wants to reboot.
+ if (AskToReboot(device, chosen_action)) {
+ return Device::REBOOT;
+ }
+ break;
+
case Device::WIPE_DATA:
save_current_log = true;
if (ui->IsTextVisible()) {
@@ -396,6 +460,9 @@
case Device::ENTER_RESCUE: {
save_current_log = true;
+ update_in_progress = true;
+ WriteUpdateInProgress();
+
bool adb = true;
Device::BuiltinAction reboot_action;
if (chosen_action == Device::ENTER_RESCUE) {
@@ -414,12 +481,15 @@
return reboot_action;
}
- if (status != INSTALL_SUCCESS) {
+ if (status == INSTALL_SUCCESS) {
+ update_in_progress = false;
+ if (!ui->IsTextVisible()) {
+ return Device::NO_ACTION; // reboot if logs aren't visible
+ }
+ } else {
ui->SetBackground(RecoveryUI::ERROR);
ui->Print("Installation aborted.\n");
copy_logs(save_current_log);
- } else if (!ui->IsTextVisible()) {
- return Device::NO_ACTION; // reboot if logs aren't visible
}
break;
}
@@ -437,7 +507,13 @@
screen_ui->CheckBackgroundTextImages();
break;
}
+
case Device::MOUNT_SYSTEM:
+ // For Virtual A/B, set up the snapshot devices (if exist).
+ if (!CreateSnapshotPartitions()) {
+ ui->Print("Virtual A/B: snapshot partitions creation failed.\n");
+ break;
+ }
if (ensure_path_mounted_at(android::fs_mgr::GetSystemRoot(), "/mnt/system") != -1) {
ui->Print("Mounted /system.\n");
}
@@ -517,7 +593,6 @@
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 },
{ "install_with_fuse", no_argument, nullptr, 0 },
{ "just_exit", no_argument, nullptr, 'x' },
{ "locale", required_argument, nullptr, 0 },
@@ -550,7 +625,6 @@
bool rescue = false;
bool just_exit = false;
bool shutdown_after = false;
- bool fsck_unshare_blocks = false;
int retry_count = 0;
bool security_update = false;
std::string locale;
@@ -573,9 +647,7 @@
break;
case 0: {
std::string option = OPTIONS[option_index].name;
- if (option == "fsck_unshare_blocks") {
- fsck_unshare_blocks = true;
- } else if (option == "install_with_fuse") {
+ if (option == "install_with_fuse") {
install_with_fuse = true;
} else if (option == "locale" || option == "fastboot" || option == "reason") {
// Handled in recovery_main.cpp
@@ -772,10 +844,6 @@
save_current_log = true;
status = ApplyFromAdb(device, true /* rescue_mode */, &next_action);
ui->Print("\nInstall from ADB complete (status: %d).\n", status);
- } else if (fsck_unshare_blocks) {
- if (!do_fsck_unshare_blocks()) {
- status = INSTALL_ERROR;
- }
} else if (!just_exit) {
// If this is an eng or userdebug build, automatically turn on the text display if no command
// is specified. Note that this should be called before setting the background to avoid
diff --git a/recovery_main.cpp b/recovery_main.cpp
index 89253dc..30a1fc0 100644
--- a/recovery_main.cpp
+++ b/recovery_main.cpp
@@ -69,6 +69,10 @@
return android::base::GetBoolProperty("ro.debuggable", false);
}
+static bool IsDeviceUnlocked() {
+ return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", "");
+}
+
static void UiLogger(android::base::LogId /* id */, android::base::LogSeverity severity,
const char* /* tag */, const char* /* file */, unsigned int /* line */,
const char* message) {
@@ -463,7 +467,9 @@
listener_thread.detach();
while (true) {
- std::string usb_config = fastboot ? "fastboot" : IsRoDebuggable() ? "adb" : "none";
+ // We start adbd in recovery for the device with userdebug build or a unlocked bootloader.
+ std::string usb_config =
+ fastboot ? "fastboot" : IsRoDebuggable() || IsDeviceUnlocked() ? "adb" : "none";
std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
if (usb_config != usb_state) {
if (!SetUsbConfig("none")) {
diff --git a/recovery_ui/screen_ui.cpp b/recovery_ui/screen_ui.cpp
index 087fc0e..6dcb161 100644
--- a/recovery_ui/screen_ui.cpp
+++ b/recovery_ui/screen_ui.cpp
@@ -448,7 +448,9 @@
int frame_height = gr_get_height(frame);
int frame_x = (ScreenWidth() - frame_width) / 2;
int frame_y = GetAnimationBaseline();
- DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
+ if (frame_x >= 0 && frame_y >= 0 && (frame_x + frame_width) < ScreenWidth() &&
+ (frame_y + frame_height) < ScreenHeight())
+ DrawSurface(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
}
if (progressBarType != EMPTY) {
diff --git a/recovery_utils/roots.cpp b/recovery_utils/roots.cpp
index fe3a07a..58a3139 100644
--- a/recovery_utils/roots.cpp
+++ b/recovery_utils/roots.cpp
@@ -30,6 +30,7 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cryptfs.h>
@@ -152,6 +153,14 @@
return -1;
}
+ bool needs_casefold = false;
+ bool needs_projid = false;
+
+ if (volume == "/data") {
+ needs_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false);
+ needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false);
+ }
+
// If there's a key_loc that looks like a path, it should be a block device for storing encryption
// metadata. Wipe it too.
if (!v->key_loc.empty() && v->key_loc[0] == '/') {
@@ -187,6 +196,21 @@
"/system/bin/mke2fs", "-F", "-t", "ext4", "-b", std::to_string(kBlockSize),
};
+ // Project ID's require wider inodes. The Quotas themselves are enabled by tune2fs on boot.
+ if (needs_projid) {
+ mke2fs_args.push_back("-I");
+ mke2fs_args.push_back("512");
+ }
+
+ if (v->fs_mgr_flags.ext_meta_csum) {
+ mke2fs_args.push_back("-O");
+ mke2fs_args.push_back("metadata_csum");
+ mke2fs_args.push_back("-O");
+ mke2fs_args.push_back("64bit");
+ mke2fs_args.push_back("-O");
+ mke2fs_args.push_back("extent");
+ }
+
int raid_stride = v->logical_blk_size / kBlockSize;
int raid_stripe_width = v->erase_blk_size / kBlockSize;
// stride should be the max of 8KB and logical block size
@@ -224,8 +248,18 @@
"/system/bin/make_f2fs",
"-g",
"android",
- v->blk_device,
};
+ if (needs_projid) {
+ make_f2fs_cmd.push_back("-O");
+ make_f2fs_cmd.push_back("project_quota,extra_attr");
+ }
+ if (needs_casefold) {
+ make_f2fs_cmd.push_back("-O");
+ make_f2fs_cmd.push_back("casefold");
+ make_f2fs_cmd.push_back("-C");
+ make_f2fs_cmd.push_back("utf8");
+ }
+ make_f2fs_cmd.push_back(v->blk_device);
if (length >= kSectorSize) {
make_f2fs_cmd.push_back(std::to_string(length / kSectorSize));
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 5b881e3..3d22390 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -39,6 +39,7 @@
android: {
shared_libs: [
"libutils",
+ "libvndksupport",
],
},
@@ -81,7 +82,6 @@
"libotautil",
"libhealthhalutils",
- "libvintf_recovery",
"libvintf",
"android.hardware.health@2.0",
@@ -90,12 +90,28 @@
"libfs_mgr",
"libhidl-gen-utils",
"libhidlbase",
- "libbinderthreadstate",
"liblp",
- "libvndksupport",
"libtinyxml2",
]
+// recovery image for unittests.
+// ========================================================
+genrule {
+ name: "recovery_image",
+ cmd: "cat $(location testdata/recovery_head) <(cat $(location testdata/recovery_body) | $(location minigzip)) $(location testdata/recovery_tail) > $(out)",
+ srcs: [
+ "testdata/recovery_head",
+ "testdata/recovery_body",
+ "testdata/recovery_tail",
+ ],
+ tools: [
+ "minigzip",
+ ],
+ out: [
+ "testdata/recovery.img",
+ ],
+}
+
cc_test {
name: "recovery_unit_test",
isolated: true,
@@ -129,6 +145,7 @@
data: [
"testdata/*",
+ ":recovery_image",
":res-testdata",
],
}
diff --git a/tests/testdata/recovery.img b/tests/testdata/recovery.img
deleted file mode 100644
index b862e6f..0000000
--- a/tests/testdata/recovery.img
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/recovery_body b/tests/testdata/recovery_body
new file mode 100644
index 0000000..48d7c10
--- /dev/null
+++ b/tests/testdata/recovery_body
Binary files differ
diff --git a/tests/testdata/recovery_head b/tests/testdata/recovery_head
new file mode 100644
index 0000000..7f494d0
--- /dev/null
+++ b/tests/testdata/recovery_head
Binary files differ
diff --git a/tests/testdata/recovery_tail b/tests/testdata/recovery_tail
new file mode 100644
index 0000000..7fe2c6c
--- /dev/null
+++ b/tests/testdata/recovery_tail
Binary files differ
diff --git a/tests/unit/bootloader_message_test.cpp b/tests/unit/bootloader_message_test.cpp
index 95d875e..731c8fe 100644
--- a/tests/unit/bootloader_message_test.cpp
+++ b/tests/unit/bootloader_message_test.cpp
@@ -118,37 +118,3 @@
ASSERT_EQ(std::string(sizeof(boot.reserved), '\0'),
std::string(boot.reserved, sizeof(boot.reserved)));
}
-
-TEST(BootloaderMessageTest, WriteMiscPartitionVendorSpace) {
- TemporaryFile temp_misc;
- ASSERT_TRUE(android::base::WriteStringToFile(std::string(4096, '\x00'), temp_misc.path));
- SetMiscBlockDeviceForTest(temp_misc.path);
-
- constexpr std::string_view kTestMessage = "kTestMessage";
- std::string err;
- ASSERT_TRUE(WriteMiscPartitionVendorSpace(kTestMessage.data(), kTestMessage.size(), 0, &err));
-
- std::string message;
- message.resize(kTestMessage.size());
- ASSERT_TRUE(ReadMiscPartitionVendorSpace(message.data(), message.size(), 0, &err));
- ASSERT_EQ(kTestMessage, message);
-
- // Write with an offset.
- ASSERT_TRUE(WriteMiscPartitionVendorSpace("\x00\x00", 2, 5, &err));
- ASSERT_TRUE(ReadMiscPartitionVendorSpace(message.data(), message.size(), 0, &err));
- ASSERT_EQ("kTest\x00\x00ssage"s, message);
-
- // Write with the right size.
- auto start_offset =
- WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC - kTestMessage.size();
- ASSERT_TRUE(
- WriteMiscPartitionVendorSpace(kTestMessage.data(), kTestMessage.size(), start_offset, &err));
-
- // Out-of-bound write.
- ASSERT_FALSE(WriteMiscPartitionVendorSpace(kTestMessage.data(), kTestMessage.size(),
- start_offset + 1, &err));
-
- // Message won't fit.
- std::string long_message(WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC + 1, 'a');
- ASSERT_FALSE(WriteMiscPartitionVendorSpace(long_message.data(), long_message.size(), 0, &err));
-}
diff --git a/tests/unit/install_test.cpp b/tests/unit/install_test.cpp
index 4ec4099..370fbdc 100644
--- a/tests/unit/install_test.cpp
+++ b/tests/unit/install_test.cpp
@@ -28,7 +28,6 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <gtest/gtest.h>
-#include <vintf/VintfObjectRecovery.h>
#include <ziparchive/zip_archive.h>
#include <ziparchive/zip_writer.h>
@@ -50,29 +49,6 @@
ASSERT_EQ(0, fclose(zip_file));
}
-TEST(InstallTest, verify_package_compatibility_no_entry) {
- TemporaryFile temp_file;
- // The archive must have something to be opened correctly.
- BuildZipArchive({ { "dummy_entry", "" } }, temp_file.release(), kCompressStored);
-
- // Doesn't contain compatibility zip entry.
- ZipArchiveHandle zip;
- ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- ASSERT_TRUE(verify_package_compatibility(zip));
- CloseArchive(zip);
-}
-
-TEST(InstallTest, verify_package_compatibility_invalid_entry) {
- TemporaryFile temp_file;
- BuildZipArchive({ { "compatibility.zip", "" } }, temp_file.release(), kCompressStored);
-
- // Empty compatibility zip entry.
- ZipArchiveHandle zip;
- ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- ASSERT_FALSE(verify_package_compatibility(zip));
- CloseArchive(zip);
-}
-
TEST(InstallTest, read_metadata_from_package_smoke) {
TemporaryFile temp_file;
const std::string content("abc=defg");
@@ -134,64 +110,6 @@
ASSERT_EQ(expected, read_partition_list);
}
-TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
- TemporaryFile compatibility_zip_file;
- std::string malformed_xml = "malformed";
- BuildZipArchive({ { "system_manifest.xml", malformed_xml } }, compatibility_zip_file.release(),
- kCompressDeflated);
-
- TemporaryFile temp_file;
- std::string compatibility_zip_content;
- ASSERT_TRUE(
- android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
- BuildZipArchive({ { "compatibility.zip", compatibility_zip_content } }, temp_file.release(),
- kCompressStored);
-
- ZipArchiveHandle zip;
- ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- std::vector<std::string> compatibility_info;
- compatibility_info.push_back(malformed_xml);
- // Malformed compatibility zip is expected to be rejected by libvintf. But we defer that to
- // libvintf.
- std::string err;
- bool result =
- android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
- ASSERT_EQ(result, verify_package_compatibility(zip));
- CloseArchive(zip);
-}
-
-TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml) {
- static constexpr const char* system_manifest_xml_path = "/system/manifest.xml";
- if (access(system_manifest_xml_path, R_OK) == -1) {
- GTEST_LOG_(INFO) << "Test skipped on devices w/o /system/manifest.xml.";
- return;
- }
- std::string system_manifest_xml_content;
- ASSERT_TRUE(
- android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content));
- TemporaryFile compatibility_zip_file;
- BuildZipArchive({ { "system_manifest.xml", system_manifest_xml_content } },
- compatibility_zip_file.release(), kCompressDeflated);
-
- TemporaryFile temp_file;
- std::string compatibility_zip_content;
- ASSERT_TRUE(
- android::base::ReadFileToString(compatibility_zip_file.path, &compatibility_zip_content));
- BuildZipArchive({ { "compatibility.zip", compatibility_zip_content } }, temp_file.release(),
- kCompressStored);
-
- ZipArchiveHandle zip;
- ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
- std::vector<std::string> compatibility_info;
- compatibility_info.push_back(system_manifest_xml_content);
- std::string err;
- bool result =
- android::vintf::VintfObjectRecovery::CheckCompatibility(compatibility_info, &err) == 0;
- // Make sure the result is consistent with libvintf library.
- ASSERT_EQ(result, verify_package_compatibility(zip));
- CloseArchive(zip);
-}
-
TEST(InstallTest, SetUpNonAbUpdateCommands) {
TemporaryFile temp_file;
static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
diff --git a/tools/recovery_l10n/res/values-gl/strings.xml b/tools/recovery_l10n/res/values-gl/strings.xml
index e6f2ffd..e51b36d 100644
--- a/tools/recovery_l10n/res/values-gl/strings.xml
+++ b/tools/recovery_l10n/res/values-gl/strings.xml
@@ -6,9 +6,9 @@
<string name="recovery_no_command" msgid="4465476568623024327">"Non hai ningún comando"</string>
<string name="recovery_error" msgid="5748178989622716736">"Erro"</string>
<string name="recovery_installing_security" msgid="9184031299717114342">"Instalando actualización de seguranza"</string>
- <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Non se puido cargar o sistema Android. Os teus datos poden estar danados. Se segue aparecendo esta mensaxe, pode ser necesario restablecer os datos de fábrica e borrar todos os datos do usuario almacenados neste dispositivo."</string>
+ <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Non se puido cargar o sistema Android. Os teus datos poden estar danados. Se segue aparecendo esta mensaxe, pode ser necesario restablecer os datos de fábrica e borrar todos os datos de usuario almacenados neste dispositivo."</string>
<string name="recovery_try_again" msgid="7168248750158873496">"Tentar de novo"</string>
<string name="recovery_factory_data_reset" msgid="7321351565602894783">"Restablecemento dos datos de fábrica"</string>
- <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Queres borrar todos os datos do usuario?\n\n ESTA ACCIÓN NON SE PODE DESFACER."</string>
+ <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Queres borrar todos os datos de usuario?\n\n ESTA ACCIÓN NON SE PODE DESFACER."</string>
<string name="recovery_cancel_wipe_data" msgid="66987687653647384">"Cancelar"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-in/strings.xml b/tools/recovery_l10n/res/values-in/strings.xml
index 43c9deb..15a78ec 100644
--- a/tools/recovery_l10n/res/values-in/strings.xml
+++ b/tools/recovery_l10n/res/values-in/strings.xml
@@ -9,6 +9,6 @@
<string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Tidak dapat memuat sistem Android. Data Anda mungkin rusak. Jika terus mendapatkan pesan ini, Anda mungkin perlu melakukan reset ke setelan pabrik dan menghapus semua data pengguna yang disimpan di perangkat ini."</string>
<string name="recovery_try_again" msgid="7168248750158873496">"Coba lagi"</string>
<string name="recovery_factory_data_reset" msgid="7321351565602894783">"Reset ke setelan pabrik"</string>
- <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Hapus total semua data pengguna?\n\n TINDAKAN INI TIDAK DAPAT DIURUNGKAN!"</string>
+ <string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"Wipe semua data pengguna?\n\n TINDAKAN INI TIDAK DAPAT DIURUNGKAN!"</string>
<string name="recovery_cancel_wipe_data" msgid="66987687653647384">"Batal"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-ja/strings.xml b/tools/recovery_l10n/res/values-ja/strings.xml
index 2d6c0ab..3d66372 100644
--- a/tools/recovery_l10n/res/values-ja/strings.xml
+++ b/tools/recovery_l10n/res/values-ja/strings.xml
@@ -6,7 +6,7 @@
<string name="recovery_no_command" msgid="4465476568623024327">"コマンドが指定されていません"</string>
<string name="recovery_error" msgid="5748178989622716736">"エラーが発生しました。"</string>
<string name="recovery_installing_security" msgid="9184031299717114342">"セキュリティ アップデートをインストールしています"</string>
- <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Android システムを読み込めません。データが破損している可能性があります。このメッセージが引き続き表示される場合は、データの初期化を行い、このデバイスに保存されているすべてのユーザー データを消去することが必要な場合があります。"</string>
+ <string name="recovery_wipe_data_menu_header" msgid="550255032058254478">"Android システムを読み込めません。データが破損している可能性があります。このメッセージが引き続き表示される場合は、データの初期化を行い、この端末に保存されているすべてのユーザー データを消去することが必要な場合があります。"</string>
<string name="recovery_try_again" msgid="7168248750158873496">"再試行"</string>
<string name="recovery_factory_data_reset" msgid="7321351565602894783">"データの初期化"</string>
<string name="recovery_wipe_data_confirmation" msgid="5439823343348043954">"すべてのユーザー データをワイプしますか?\n\nこの操作は元に戻せません。"</string>
diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp
index d04c455..a042f90 100644
--- a/update_verifier/update_verifier.cpp
+++ b/update_verifier/update_verifier.cpp
@@ -371,6 +371,10 @@
return reboot_device();
}
LOG(INFO) << "Marked slot " << current_slot << " as booted successfully.";
+ // Clears the warm reset flag for next reboot.
+ if (!android::base::SetProperty("ota.warm_reset", "0")) {
+ LOG(WARNING) << "Failed to reset the warm reset flag";
+ }
} else {
LOG(INFO) << "Deferred marking slot " << current_slot << " as booted successfully.";
}
diff --git a/updater/Android.bp b/updater/Android.bp
index 8a60ef7..f00a192 100644
--- a/updater/Android.bp
+++ b/updater/Android.bp
@@ -13,11 +13,7 @@
// limitations under the License.
cc_defaults {
- name: "libupdater_defaults",
-
- defaults: [
- "recovery_defaults",
- ],
+ name: "libupdater_static_libs",
static_libs: [
"libapplypatch",
@@ -29,6 +25,7 @@
"libdm",
"libfec",
"libfec_rs",
+ "libavb",
"libverity_tree",
"libgtest_prod",
"liblog",
@@ -45,6 +42,15 @@
"libcutils",
"libutils",
],
+}
+
+cc_defaults {
+ name: "libupdater_defaults",
+
+ defaults: [
+ "recovery_defaults",
+ "libupdater_static_libs",
+ ],
shared_libs: [
"libcrypto",
@@ -64,7 +70,7 @@
"libext2_uuid",
"libext2_e2p",
"libext2fs",
- ]
+ ],
}
cc_library_static {
@@ -155,3 +161,29 @@
"include",
],
}
+
+cc_binary_host {
+ name: "update_host_simulator",
+ defaults: ["libupdater_static_libs"],
+
+ srcs: ["update_simulator_main.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ static_libs: [
+ "libupdater_host",
+ "libupdater_core",
+ "libcrypto_static",
+ "libfstab",
+ "libc++fs",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/updater/Android.mk b/updater/Android.mk
index 6f54d89..46300d9 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -32,6 +32,7 @@
libdm \
libfec \
libfec_rs \
+ libavb \
libverity_tree \
libgtest_prod \
liblog \
@@ -111,32 +112,3 @@
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
-
-# TODO(xunchang) move to bp file
-# update_host_simulator (host executable)
-# ===============================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := update_host_simulator
-LOCAL_MODULE_HOST_OS := linux
-
-LOCAL_SRC_FILES := \
- update_simulator_main.cpp
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS := \
- -Wall \
- -Werror
-
-LOCAL_STATIC_LIBRARIES := \
- libupdater_host \
- libupdater_core \
- $(updater_common_static_libraries) \
- libfstab \
- libc++fs
-
-LOCAL_MODULE_CLASS := EXECUTABLES
-
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/updater_sample/AndroidManifest.xml b/updater_sample/AndroidManifest.xml
index 0a25116..981cd8e 100644
--- a/updater_sample/AndroidManifest.xml
+++ b/updater_sample/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
+ <uses-permission android:name="android.permission.INTERNET"/>
<application
android:icon="@mipmap/ic_launcher"