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:
parent
43482de3f9
commit
f41c7bbb96
11 changed files with 92 additions and 7 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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") ||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue