libfiemap: Add helpers to remove images from recovery.

ImageManager can map images in recovery, but not delete them, because
/data is not mounted. libsnapshot handles this by storing extra state
files, but this is complex to manage and inconvenient for
fs_mgr_overlayfs.

Instead, this patch introduces two new calls:

 - DisableImage(), which indicates the image should not be used. This is
   implemented by adding a new DISABLED attribute to
   LpPartitionMetadata. CreateLogicalPartitions ignores this flag, and
   thus recovery/fastbootd can disable the scratch partition and
   communicate that it can be deleted. This cannot be called from binder
   since it is intended for recovery/first-stage init only.

 - RemoveDisabledImages(), which walks the images for a given folder on
   /metadata and deletes any that are disabled. This can be called from
   binder.

Note that there is no metadata version bump for this flag. It's
considered to be included in the flag list for minor version 1, and
currently is not used for the actual super partition.

Bug: 134949511
Test: adb remount, fastboot flash system
Test: fiemap_image_test
Change-Id: Iaeca2d1eddb5637dd9a20202cafd11ae60b4d0e3
This commit is contained in:
David Anderson 2019-12-16 19:52:14 -08:00
parent 43482de3f9
commit f41c7bbb96
11 changed files with 92 additions and 7 deletions

View file

@ -151,6 +151,10 @@ bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& supe
LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
continue;
}
if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
LINFO << "Skipping disabled partition: " << GetPartitionName(partition);
continue;
}
params.partition = &partition;

View file

@ -43,6 +43,8 @@ class ImageManagerBinder final : public IImageManager {
std::string* dev) override;
bool ZeroFillNewImage(const std::string& name, uint64_t bytes) override;
bool RemoveAllImages() override;
bool DisableImage(const std::string& name) override;
bool RemoveDisabledImages() override;
std::vector<std::string> GetAllBackingImages() override;
@ -163,6 +165,21 @@ bool ImageManagerBinder::RemoveAllImages() {
return true;
}
bool ImageManagerBinder::DisableImage(const std::string&) {
LOG(ERROR) << __PRETTY_FUNCTION__ << " is not available over binder";
return false;
}
bool ImageManagerBinder::RemoveDisabledImages() {
auto status = manager_->removeDisabledImages();
if (!status.isOk()) {
LOG(ERROR) << __PRETTY_FUNCTION__
<< " binder returned: " << status.exceptionMessage().string();
return false;
}
return true;
}
static android::sp<IGsid> AcquireIGsid(const std::chrono::milliseconds& timeout_ms) {
if (android::base::GetProperty("init.svc.gsid", "") != "running") {
if (!android::base::SetProperty("ctl.start", "gsid") ||

View file

@ -632,6 +632,27 @@ bool ImageManager::Validate() {
return true;
}
bool ImageManager::DisableImage(const std::string& name) {
return AddAttributes(metadata_dir_, name, LP_PARTITION_ATTR_DISABLED);
}
bool ImageManager::RemoveDisabledImages() {
if (!MetadataExists(metadata_dir_)) {
return true;
}
auto metadata = OpenMetadata(metadata_dir_);
if (!metadata) {
return false;
}
bool ok = true;
for (const auto& partition : metadata->partitions) {
ok &= DeleteBackingImage(GetPartitionName(partition));
}
return ok;
}
std::unique_ptr<MappedDevice> MappedDevice::Open(IImageManager* manager,
const std::chrono::milliseconds& timeout_ms,
const std::string& name) {

View file

@ -112,6 +112,14 @@ TEST_F(NativeTest, CreateAndMap) {
ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), "");
}
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_->RemoveDisabledImages());
ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
}
// This fixture is for tests against a simulated device environment. Rather
// than use /data, we create an image and then layer a new filesystem within
// it. Each test then decides how to mount and create layered images. This

View file

@ -84,6 +84,16 @@ class IImageManager {
virtual bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
std::string* dev) = 0;
// Mark an image as disabled. This is useful for marking an image as
// will-be-deleted in recovery, since recovery cannot mount /data.
//
// This is not available in binder, since it is intended for recovery.
// When binder is available, images can simply be removed.
virtual bool DisableImage(const std::string& name) = 0;
// Remove all images that been marked as disabled.
virtual bool RemoveDisabledImages() = 0;
// Get all backing image names.
virtual std::vector<std::string> GetAllBackingImages() = 0;
@ -119,6 +129,8 @@ class ImageManager final : public IImageManager {
bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
std::string* dev) override;
bool RemoveAllImages() override;
bool DisableImage(const std::string& name) override;
bool RemoveDisabledImages() override;
std::vector<std::string> GetAllBackingImages();
// Same as CreateBackingImage, but provides a progress notification.

View file

@ -192,5 +192,23 @@ bool UpdateMetadata(const std::string& metadata_dir, const std::string& partitio
return SaveMetadata(builder.get(), metadata_dir);
}
bool AddAttributes(const std::string& metadata_dir, const std::string& partition_name,
uint32_t attributes) {
auto metadata = OpenMetadata(metadata_dir);
if (!metadata) {
return false;
}
auto builder = MetadataBuilder::New(*metadata.get());
if (!builder) {
return false;
}
auto partition = builder->FindPartition(partition_name);
if (!partition) {
return false;
}
partition->set_attributes(partition->attributes() | attributes);
return SaveMetadata(builder.get(), metadata_dir);
}
} // namespace fiemap
} // namespace android

View file

@ -29,6 +29,8 @@ bool MetadataExists(const std::string& metadata_dir);
std::unique_ptr<android::fs_mgr::LpMetadata> OpenMetadata(const std::string& metadata_dir);
bool UpdateMetadata(const std::string& metadata_dir, const std::string& partition_name,
SplitFiemap* file, uint64_t partition_size, bool readonly);
bool AddAttributes(const std::string& metadata_dir, const std::string& partition_name,
uint32_t attributes);
bool RemoveImageMetadata(const std::string& metadata_dir, const std::string& partition_name);
bool RemoveAllMetadata(const std::string& dir);

View file

@ -852,7 +852,7 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
return nullptr;
}
if (partition->attributes() & LP_PARTITION_ATTR_UPDATED) {
if (partition->attributes() & LP_PARTITION_ATTRIBUTE_MASK_V1) {
static const uint16_t kMinVersion = LP_METADATA_VERSION_FOR_UPDATED_ATTR;
metadata->header.minor_version = std::max(metadata->header.minor_version, kMinVersion);
}

View file

@ -145,6 +145,7 @@ class Partition final {
std::vector<std::unique_ptr<Extent>> extents_;
uint32_t attributes_;
uint64_t size_;
bool disabled_;
};
// An interval in the metadata. This is similar to a LinearExtent with one difference.

View file

@ -72,13 +72,17 @@ extern "C" {
*/
#define LP_PARTITION_ATTR_UPDATED (1 << 2)
/* This flag marks a partition as disabled. It should not be used or mapped. */
#define LP_PARTITION_ATTR_DISABLED (1 << 3)
/* Mask that defines all valid attributes. When changing this, make sure to
* update ParseMetadata().
*/
#define LP_PARTITION_ATTRIBUTE_MASK_V0 \
(LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTR_UPDATED)
#define LP_PARTITION_ATTRIBUTE_MASK LP_PARTITION_ATTRIBUTE_MASK_V1
#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTR_UPDATED | LP_PARTITION_ATTR_DISABLED)
#define LP_PARTITION_ATTRIBUTE_MASK \
(LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTRIBUTE_MASK_V1)
/* Default name of the physical partition that holds logical partition entries.
* The layout of this partition will look like:

View file

@ -280,11 +280,9 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
return nullptr;
}
uint32_t valid_attributes = 0;
uint32_t valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
if (metadata->header.minor_version >= LP_METADATA_VERSION_FOR_UPDATED_ATTR) {
valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V1;
} else {
valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
valid_attributes |= LP_PARTITION_ATTRIBUTE_MASK_V1;
}
// ValidateTableSize ensured that |cursor| is valid for the number of