Loading fs_mgr/libsnapshot/include/libsnapshot/auto_device.h 0 → 100644 +40 −0 Original line number Diff line number Diff line // 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 fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +19 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -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); Loading fs_mgr/libsnapshot/snapshot.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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_; Loading Loading @@ -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 fs_mgr/libsnapshot/snapshot_test.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -1097,6 +1159,7 @@ int main(int argc, char** argv) { } // Clean up previous run. MetadataMountedTest().TearDown(); SnapshotUpdateTest().Cleanup(); SnapshotTest().Cleanup(); Loading fs_mgr/libsnapshot/test_helpers.h +3 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/auto_device.h 0 → 100644 +40 −0 Original line number Diff line number Diff line // 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
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +19 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -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); Loading
fs_mgr/libsnapshot/snapshot.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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_; Loading Loading @@ -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
fs_mgr/libsnapshot/snapshot_test.cpp +63 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -1097,6 +1159,7 @@ int main(int argc, char** argv) { } // Clean up previous run. MetadataMountedTest().TearDown(); SnapshotUpdateTest().Cleanup(); SnapshotTest().Cleanup(); Loading
fs_mgr/libsnapshot/test_helpers.h +3 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading