fastbootd: Remove all scratch partitions on update-super.

This ensures that the dynamic "scratch" partition is removed when doing
a flashall operation.

If "scratch" is on /data, disable the partition. Add IsImageDisabled to
ImageManager so EnsureScratchMapped can skip mapping it. Also, fix
"scratch" not getting unmapped if on /data.

Bug: 205987817
Test: adb remount
      adb sync
      adb reboot fastboot
      fastboot flashall --skip-reboot # no errors
Test: adb-remount-test.sh
Change-Id: I4b9702e1dac15fb663635506fb50a8274e1e10d1
This commit is contained in:
David Anderson 2022-02-08 22:06:44 -08:00
parent 78b86ae297
commit 982c3410c7
7 changed files with 101 additions and 29 deletions

View file

@ -186,6 +186,11 @@ int Flash(FastbootDevice* device, const std::string& partition_name) {
return result;
}
static void RemoveScratchPartition() {
AutoMountMetadata mount_metadata;
android::fs_mgr::TeardownAllOverlayForMountPoint();
}
bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) {
std::vector<char> data = std::move(device->download_data());
if (data.empty()) {
@ -218,7 +223,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip
if (!FlashPartitionTable(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to flash new partition table");
}
android::fs_mgr::TeardownAllOverlayForMountPoint();
RemoveScratchPartition();
sync();
return device->WriteOkay("Successfully flashed partition table");
}
@ -262,7 +267,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip
if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
android::fs_mgr::TeardownAllOverlayForMountPoint();
RemoveScratchPartition();
sync();
return device->WriteOkay("Successfully updated partition table");
}

View file

@ -33,6 +33,7 @@
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <vector>
@ -1396,18 +1397,35 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool*
return ret;
}
struct MapInfo {
// If set, partition is owned by ImageManager.
std::unique_ptr<IImageManager> images;
// If set, and images is null, this is a DAP partition.
std::string name;
// If set, and images and name are empty, this is a non-dynamic partition.
std::string device;
MapInfo() = default;
MapInfo(MapInfo&&) = default;
~MapInfo() {
if (images) {
images->UnmapImageDevice(name);
} else if (!name.empty()) {
DestroyLogicalPartition(name);
}
}
};
// Note: This function never returns the DSU scratch device in recovery or fastbootd,
// because the DSU scratch is created in the first-stage-mount, which is not run in recovery.
static bool EnsureScratchMapped(std::string* device, bool* mapped) {
*mapped = false;
*device = GetBootScratchDevice();
if (!device->empty()) {
return true;
static std::optional<MapInfo> EnsureScratchMapped() {
MapInfo info;
info.device = GetBootScratchDevice();
if (!info.device.empty()) {
return {std::move(info)};
}
if (!fs_mgr_in_recovery()) {
errno = EINVAL;
return false;
return {};
}
auto partition_name = android::base::Basename(kScratchMountPoint);
@ -1417,11 +1435,15 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) {
// would otherwise always be mapped.
auto images = IImageManager::Open("remount", 10s);
if (images && images->BackingImageExists(partition_name)) {
if (!images->MapImageDevice(partition_name, 10s, device)) {
return false;
if (images->IsImageDisabled(partition_name)) {
return {};
}
*mapped = true;
return true;
if (!images->MapImageDevice(partition_name, 10s, &info.device)) {
return {};
}
info.name = partition_name;
info.images = std::move(images);
return {std::move(info)};
}
// Avoid uart spam by first checking for a scratch partition.
@ -1429,12 +1451,12 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) {
auto super_device = fs_mgr_overlayfs_super_device(metadata_slot);
auto metadata = ReadCurrentMetadata(super_device);
if (!metadata) {
return false;
return {};
}
auto partition = FindPartition(*metadata.get(), partition_name);
if (!partition) {
return false;
return {};
}
CreateLogicalPartitionParams params = {
@ -1444,11 +1466,11 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) {
.force_writable = true,
.timeout_ms = 10s,
};
if (!CreateLogicalPartition(params, device)) {
return false;
if (!CreateLogicalPartition(params, &info.device)) {
return {};
}
*mapped = true;
return true;
info.name = partition_name;
return {std::move(info)};
}
// This should only be reachable in recovery, where DSU scratch is not
@ -1602,26 +1624,35 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) {
fs_mgr_overlayfs_teardown_one(overlay_mount_point, teardown_dir, ignore_change);
}
// Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
bool mapped = false;
std::string scratch_device;
if (EnsureScratchMapped(&scratch_device, &mapped)) {
if (mount_point.empty()) {
// Throw away the entire partition.
auto partition_name = android::base::Basename(kScratchMountPoint);
auto images = IImageManager::Open("remount", 10s);
if (images && images->BackingImageExists(partition_name)) {
if (images->DisableImage(partition_name)) {
LOG(INFO) << "Disabled scratch partition for: " << kScratchMountPoint;
} else {
LOG(ERROR) << "Unable to disable scratch partition for " << kScratchMountPoint;
}
}
}
if (auto info = EnsureScratchMapped(); info.has_value()) {
// Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
fs_mgr_overlayfs_umount_scratch();
if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) {
bool should_destroy_scratch = false;
fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change,
&should_destroy_scratch);
fs_mgr_overlayfs_umount_scratch();
if (should_destroy_scratch) {
fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr);
}
fs_mgr_overlayfs_umount_scratch();
}
if (mapped) {
DestroyLogicalPartition(android::base::Basename(kScratchMountPoint));
}
}
// Teardown DSU overlay if present.
std::string scratch_device;
if (MapDsuScratchDevice(&scratch_device)) {
fs_mgr_overlayfs_umount_scratch();
if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {

View file

@ -66,6 +66,7 @@ class ImageManagerBinder final : public IImageManager {
bool RemoveDisabledImages() override;
bool GetMappedImageDevice(const std::string& name, std::string* device) override;
bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
bool IsImageDisabled(const std::string& name) override;
std::vector<std::string> GetAllBackingImages() override;
@ -219,6 +220,17 @@ bool ImageManagerBinder::GetMappedImageDevice(const std::string& name, std::stri
return !device->empty();
}
bool ImageManagerBinder::IsImageDisabled(const std::string& name) {
bool retval;
auto status = manager_->isImageDisabled(name, &retval);
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
<< " binder returned: " << status.exceptionMessage().string();
return false;
}
return retval;
}
bool ImageManagerBinder::MapAllImages(const std::function<bool(std::set<std::string>)>&) {
LOG(ERROR) << __PRETTY_FUNCTION__ << " not available over binder";
return false;

View file

@ -854,6 +854,24 @@ bool ImageManager::ValidateImageMaps() {
return true;
}
bool ImageManager::IsImageDisabled(const std::string& name) {
if (!MetadataExists(metadata_dir_)) {
return true;
}
auto metadata = OpenMetadata(metadata_dir_);
if (!metadata) {
return false;
}
auto partition = FindPartition(*metadata.get(), name);
if (!partition) {
return false;
}
return !!(partition->attributes & LP_PARTITION_ATTR_DISABLED);
}
std::unique_ptr<MappedDevice> MappedDevice::Open(IImageManager* manager,
const std::chrono::milliseconds& timeout_ms,
const std::string& name) {

View file

@ -119,6 +119,7 @@ TEST_F(NativeTest, DisableImage) {
ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
ASSERT_TRUE(manager_->BackingImageExists(base_name_));
ASSERT_TRUE(manager_->DisableImage(base_name_));
ASSERT_TRUE(manager_->IsImageDisabled(base_name_));
ASSERT_TRUE(manager_->RemoveDisabledImages());
ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
}

View file

@ -131,6 +131,9 @@ class IImageManager {
virtual bool RemoveAllImages() = 0;
virtual bool UnmapImageIfExists(const std::string& name);
// Returns whether DisableImage() was called.
virtual bool IsImageDisabled(const std::string& name) = 0;
};
class ImageManager final : public IImageManager {
@ -162,6 +165,7 @@ class ImageManager final : public IImageManager {
bool RemoveDisabledImages() override;
bool GetMappedImageDevice(const std::string& name, std::string* device) override;
bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
bool IsImageDisabled(const std::string& name) override;
std::vector<std::string> GetAllBackingImages();

View file

@ -199,6 +199,7 @@ class SnapshotFuzzImageManager : public android::fiemap::IImageManager {
bool UnmapImageIfExists(const std::string& name) override {
return impl_->UnmapImageIfExists(name);
}
bool IsImageDisabled(const std::string& name) override { return impl_->IsImageDisabled(name); }
private:
std::unique_ptr<android::fiemap::IImageManager> impl_;