libsnapshot: Add EnsureMetadataMounted
In recovery, client is responsible for calling EnsureMetadataMounted before doing (almost) all operations on SnapshotManager, e.g. - CancelUpdate() before sideloading - BeginUpdate() on retrofit Virtual A/B before sideloading - Finishing merge before flashing Test: libsnapshot_test Test: recovery sideload Bug: 140749209 Change-Id: I1034a7fa74e31b6850896e61e86341239dbf2699
This commit is contained in:
parent
82f1cbea1e
commit
d2a0247538
|
@ -0,0 +1,40 @@
|
|||
// 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-base/macros.h>
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
// An abstract "device" that will be cleaned up (unmapped, unmounted, etc.) upon
|
||||
// destruction.
|
||||
struct AutoDevice {
|
||||
virtual ~AutoDevice(){};
|
||||
void Release();
|
||||
|
||||
protected:
|
||||
AutoDevice(const std::string& name) : name_(name) {}
|
||||
std::string name_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoDevice);
|
||||
AutoDevice(AutoDevice&& other) = delete;
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
|
@ -33,6 +33,8 @@
|
|||
#include <liblp/liblp.h>
|
||||
#include <update_engine/update_metadata.pb.h>
|
||||
|
||||
#include <libsnapshot/auto_device.h>
|
||||
|
||||
#ifndef FRIEND_TEST
|
||||
#define FRIEND_TEST(test_set_name, individual_test) \
|
||||
friend class test_set_name##_##individual_test##_Test
|
||||
|
@ -120,6 +122,7 @@ class SnapshotManager final {
|
|||
virtual const IPartitionOpener& GetPartitionOpener() const = 0;
|
||||
virtual bool IsOverlayfsSetup() const = 0;
|
||||
virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
|
||||
virtual bool IsRecovery() const = 0;
|
||||
};
|
||||
|
||||
~SnapshotManager();
|
||||
|
@ -209,6 +212,22 @@ class SnapshotManager final {
|
|||
// Dump debug information.
|
||||
bool Dump(std::ostream& os);
|
||||
|
||||
// Ensure metadata directory is mounted in recovery. When the returned
|
||||
// AutoDevice is destroyed, the metadata directory is automatically
|
||||
// unmounted.
|
||||
// Return nullptr if any failure.
|
||||
// In Android mode, Return an AutoDevice that does nothing
|
||||
// In recovery, return an AutoDevice that does nothing if metadata entry
|
||||
// is not found in fstab.
|
||||
// Note: if this function is called the second time before the AutoDevice returned from the
|
||||
// first call is destroyed, the device will be unmounted when any of these AutoDevices is
|
||||
// destroyed. FOr example:
|
||||
// auto a = mgr->EnsureMetadataMounted(); // mounts
|
||||
// auto b = mgr->EnsureMetadataMounted(); // does nothing
|
||||
// b.reset() // unmounts
|
||||
// a.reset() // does nothing
|
||||
std::unique_ptr<AutoDevice> EnsureMetadataMounted();
|
||||
|
||||
private:
|
||||
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
|
||||
FRIEND_TEST(SnapshotTest, CreateSnapshot);
|
||||
|
|
|
@ -77,6 +77,12 @@ using namespace std::string_literals;
|
|||
|
||||
static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
|
||||
|
||||
#ifdef __ANDROID_RECOVERY__
|
||||
constexpr bool kIsRecovery = true;
|
||||
#else
|
||||
constexpr bool kIsRecovery = false;
|
||||
#endif
|
||||
|
||||
class DeviceInfo final : public SnapshotManager::IDeviceInfo {
|
||||
public:
|
||||
std::string GetGsidDir() const override { return "ota"s; }
|
||||
|
@ -89,6 +95,7 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
|
|||
}
|
||||
bool IsOverlayfsSetup() const override { return fs_mgr_overlayfs_is_setup(); }
|
||||
bool SetBootControlMergeStatus(MergeStatus status) override;
|
||||
bool IsRecovery() const override { return kIsRecovery; }
|
||||
|
||||
private:
|
||||
android::fs_mgr::PartitionOpener opener_;
|
||||
|
@ -2065,5 +2072,14 @@ bool SnapshotManager::Dump(std::ostream& os) {
|
|||
return ok;
|
||||
}
|
||||
|
||||
std::unique_ptr<AutoDevice> SnapshotManager::EnsureMetadataMounted() {
|
||||
if (!device_->IsRecovery()) {
|
||||
// No need to mount anything in recovery.
|
||||
LOG(INFO) << "EnsureMetadataMounted does nothing in Android mode.";
|
||||
return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice());
|
||||
}
|
||||
return AutoUnmountDevice::New(device_->GetMetadataDir());
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <fs_mgr/roots.h>
|
||||
#include <fs_mgr_dm_linear.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <libdm/dm.h>
|
||||
|
@ -47,7 +48,10 @@ using android::fiemap::IImageManager;
|
|||
using android::fs_mgr::BlockDeviceInfo;
|
||||
using android::fs_mgr::CreateLogicalPartitionParams;
|
||||
using android::fs_mgr::DestroyLogicalPartition;
|
||||
using android::fs_mgr::EnsurePathMounted;
|
||||
using android::fs_mgr::EnsurePathUnmounted;
|
||||
using android::fs_mgr::Extent;
|
||||
using android::fs_mgr::Fstab;
|
||||
using android::fs_mgr::GetPartitionGroupName;
|
||||
using android::fs_mgr::GetPartitionName;
|
||||
using android::fs_mgr::Interval;
|
||||
|
@ -1056,6 +1060,64 @@ TEST_F(SnapshotUpdateTest, ReclaimCow) {
|
|||
}
|
||||
}
|
||||
|
||||
class MetadataMountedTest : public SnapshotUpdateTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
metadata_dir_ = test_device->GetMetadataDir();
|
||||
ASSERT_TRUE(ReadDefaultFstab(&fstab_));
|
||||
}
|
||||
void TearDown() override {
|
||||
SetUp();
|
||||
// Remount /metadata
|
||||
test_device->set_recovery(false);
|
||||
EXPECT_TRUE(android::fs_mgr::EnsurePathMounted(&fstab_, metadata_dir_));
|
||||
}
|
||||
AssertionResult IsMetadataMounted() {
|
||||
Fstab mounted_fstab;
|
||||
if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
|
||||
ADD_FAILURE() << "Failed to scan mounted volumes";
|
||||
return AssertionFailure() << "Failed to scan mounted volumes";
|
||||
}
|
||||
|
||||
auto entry = GetEntryForPath(&fstab_, metadata_dir_);
|
||||
if (entry == nullptr) {
|
||||
return AssertionFailure() << "No mount point found in fstab for path " << metadata_dir_;
|
||||
}
|
||||
|
||||
auto mv = GetEntryForMountPoint(&mounted_fstab, entry->mount_point);
|
||||
if (mv == nullptr) {
|
||||
return AssertionFailure() << metadata_dir_ << " is not mounted";
|
||||
}
|
||||
return AssertionSuccess() << metadata_dir_ << " is mounted";
|
||||
}
|
||||
std::string metadata_dir_;
|
||||
Fstab fstab_;
|
||||
};
|
||||
|
||||
TEST_F(MetadataMountedTest, Android) {
|
||||
auto device = sm->EnsureMetadataMounted();
|
||||
EXPECT_NE(nullptr, device);
|
||||
device.reset();
|
||||
|
||||
EXPECT_TRUE(IsMetadataMounted());
|
||||
EXPECT_TRUE(sm->CancelUpdate()) << "Metadata dir should never be unmounted in Android mode";
|
||||
}
|
||||
|
||||
TEST_F(MetadataMountedTest, Recovery) {
|
||||
test_device->set_recovery(true);
|
||||
metadata_dir_ = test_device->GetMetadataDir();
|
||||
|
||||
EXPECT_TRUE(android::fs_mgr::EnsurePathUnmounted(&fstab_, metadata_dir_));
|
||||
EXPECT_FALSE(IsMetadataMounted());
|
||||
|
||||
auto device = sm->EnsureMetadataMounted();
|
||||
EXPECT_NE(nullptr, device);
|
||||
EXPECT_TRUE(IsMetadataMounted());
|
||||
|
||||
device.reset();
|
||||
EXPECT_FALSE(IsMetadataMounted());
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
||||
|
@ -1097,6 +1159,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
// Clean up previous run.
|
||||
MetadataMountedTest().TearDown();
|
||||
SnapshotUpdateTest().Cleanup();
|
||||
SnapshotTest().Cleanup();
|
||||
|
||||
|
|
|
@ -88,17 +88,20 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
|
|||
return true;
|
||||
}
|
||||
bool IsOverlayfsSetup() const override { return false; }
|
||||
bool IsRecovery() const override { return recovery_; }
|
||||
|
||||
void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
|
||||
void set_fake_super(const std::string& path) {
|
||||
opener_ = std::make_unique<TestPartitionOpener>(path);
|
||||
}
|
||||
void set_recovery(bool value) { recovery_ = value; }
|
||||
MergeStatus merge_status() const { return merge_status_; }
|
||||
|
||||
private:
|
||||
std::string slot_suffix_ = "_a";
|
||||
std::unique_ptr<TestPartitionOpener> opener_;
|
||||
MergeStatus merge_status_;
|
||||
bool recovery_ = false;
|
||||
};
|
||||
|
||||
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <fs_mgr/roots.h>
|
||||
|
||||
using android::fs_mgr::EnsurePathMounted;
|
||||
using android::fs_mgr::EnsurePathUnmounted;
|
||||
using android::fs_mgr::Fstab;
|
||||
using android::fs_mgr::GetEntryForPath;
|
||||
using android::fs_mgr::MetadataBuilder;
|
||||
using android::fs_mgr::Partition;
|
||||
using android::fs_mgr::ReadDefaultFstab;
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
@ -109,5 +115,31 @@ bool InitializeCow(const std::string& device) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<AutoUnmountDevice> AutoUnmountDevice::New(const std::string& path) {
|
||||
Fstab fstab;
|
||||
if (!ReadDefaultFstab(&fstab)) {
|
||||
LOG(ERROR) << "Cannot read default fstab";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (GetEntryForPath(&fstab, path) == nullptr) {
|
||||
LOG(INFO) << "EnsureMetadataMounted can't find entry for " << path << ", skipping";
|
||||
return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice("", {}));
|
||||
}
|
||||
|
||||
if (!EnsurePathMounted(&fstab, path)) {
|
||||
LOG(ERROR) << "Cannot mount " << path;
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice(path, std::move(fstab)));
|
||||
}
|
||||
|
||||
AutoUnmountDevice::~AutoUnmountDevice() {
|
||||
if (name_.empty()) return;
|
||||
if (!EnsurePathUnmounted(&fstab_, name_)) {
|
||||
LOG(ERROR) << "Cannot unmount " << name_;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
@ -18,31 +18,21 @@
|
|||
#include <string>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <fstab/fstab.h>
|
||||
#include <libdm/dm.h>
|
||||
#include <libfiemap/image_manager.h>
|
||||
#include <liblp/builder.h>
|
||||
#include <libsnapshot/snapshot.h>
|
||||
#include <update_engine/update_metadata.pb.h>
|
||||
|
||||
#include <libsnapshot/auto_device.h>
|
||||
|
||||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
// Unit is sectors, this is a 4K chunk.
|
||||
static constexpr uint32_t kSnapshotChunkSize = 8;
|
||||
|
||||
struct AutoDevice {
|
||||
virtual ~AutoDevice(){};
|
||||
void Release();
|
||||
|
||||
protected:
|
||||
AutoDevice(const std::string& name) : name_(name) {}
|
||||
std::string name_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoDevice);
|
||||
AutoDevice(AutoDevice&& other) = delete;
|
||||
};
|
||||
|
||||
// A list of devices we created along the way.
|
||||
// - Whenever a device is created that is subject to GC'ed at the end of
|
||||
// this function, add it to this list.
|
||||
|
@ -103,6 +93,18 @@ struct AutoDeleteSnapshot : AutoDevice {
|
|||
SnapshotManager::LockedFile* lock_ = nullptr;
|
||||
};
|
||||
|
||||
struct AutoUnmountDevice : AutoDevice {
|
||||
// Empty object that does nothing.
|
||||
AutoUnmountDevice() : AutoDevice("") {}
|
||||
static std::unique_ptr<AutoUnmountDevice> New(const std::string& path);
|
||||
~AutoUnmountDevice();
|
||||
|
||||
private:
|
||||
AutoUnmountDevice(const std::string& path, android::fs_mgr::Fstab&& fstab)
|
||||
: AutoDevice(path), fstab_(std::move(fstab)) {}
|
||||
android::fs_mgr::Fstab fstab_;
|
||||
};
|
||||
|
||||
// Return a list of partitions in |builder| with the name ending in |suffix|.
|
||||
std::vector<android::fs_mgr::Partition*> ListPartitionsWithSuffix(
|
||||
android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
|
||||
|
|
Loading…
Reference in New Issue