Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f11ec6a authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Prototype the new API for mapping writable snapshots.

Since we can't provide a single device or fd anymore, we need to expose
a CowWriter directly. Additionally, we expose an API for reading
snapshots through the FileDescriptor abstraction.

Bug: 168554689
Test: builds
Change-Id: If7e8adbfe69c2a84d34c63d4b0adff2b3365fd82
parent 0407302a
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ cc_defaults {
    static_libs: [
        "libdm",
        "libfstab",
        "libsnapshot_cow",
        "update_metadata-protos",
    ],
    whole_static_libs: [
@@ -38,7 +39,9 @@ cc_defaults {
        "libfstab",
    ],
    header_libs: [
        "libchrome",
        "libfiemap_headers",
        "libupdate_engine_headers",
    ],
    export_static_lib_headers: [
        "update_metadata-protos",
@@ -313,8 +316,10 @@ cc_defaults {
        "libprotobuf-mutator",
    ],
    header_libs: [
        "libchrome",
        "libfiemap_headers",
        "libstorage_literals_headers",
        "libupdate_engine_headers",
    ],
    proto: {
        type: "full",
+7 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#pragma once

#include <libsnapshot/snapshot.h>
#include <payload_consumer/file_descriptor.h>

#include <gmock/gmock.h>

@@ -37,6 +38,12 @@ class MockSnapshotManager : public ISnapshotManager {
                (const android::fs_mgr::CreateLogicalPartitionParams& params,
                 std::string* snapshot_path),
                (override));
    MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
                (const std::string& partition_name, std::chrono::milliseconds timeout_ms),
                (override));
    MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenSnapshotReader,
                (const std::string& partition_name, std::chrono::milliseconds timeout_ms),
                (override));
    MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
    MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
    MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
+26 −1
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <update_engine/update_metadata.pb.h>

#include <libsnapshot/auto_device.h>
#include <libsnapshot/cow_writer.h>
#include <libsnapshot/return.h>

#ifndef FRIEND_TEST
@@ -43,6 +44,10 @@
#define DEFINED_FRIEND_TEST
#endif

namespace chromeos_update_engine {
class FileDescriptor;
}  // namespace chromeos_update_engine

namespace android {

namespace fiemap {
@@ -105,6 +110,8 @@ class ISnapshotManager {
    };
    virtual ~ISnapshotManager() = default;

    using FileDescriptor = chromeos_update_engine::FileDescriptor;

    // Begin an update. This must be called before creating any snapshots. It
    // will fail if GetUpdateState() != None.
    virtual bool BeginUpdate() = 0;
@@ -173,11 +180,25 @@ class ISnapshotManager {

    // Map a snapshotted partition for OTA clients to write to. Write-protected regions are
    // determined previously in CreateSnapshots.
    //
    // |snapshot_path| must not be nullptr.
    //
    // This method will return false if ro.virtual_ab.compression.enabled is true.
    virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                                   std::string* snapshot_path) = 0;

    // Unmap a snapshot device that's previously mapped with MapUpdateSnapshot.
    // Create an ICowWriter to build a snapshot against a target partition.
    virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) = 0;

    // Open a snapshot for reading. A file-like interface is provided through the FileDescriptor.
    // In this mode, writes are not supported.
    virtual std::unique_ptr<FileDescriptor> OpenSnapshotReader(
            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) = 0;

    // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
    // OpenSnapshotWriter, or OpenSnapshotReader. All outstanding open descriptors, writers,
    // or readers must be deleted before this is called.
    virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;

    // If this returns true, first-stage mount must call
@@ -288,6 +309,10 @@ class SnapshotManager final : public ISnapshotManager {
    Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
    bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                           std::string* snapshot_path) override;
    std::unique_ptr<ICowWriter> OpenSnapshotWriter(
            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override;
    std::unique_ptr<FileDescriptor> OpenSnapshotReader(
            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override;
    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
    bool NeedSnapshotsInFirstStageMount() override;
    bool CreateLogicalAndSnapshotPartitions(
+5 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#pragma once

#include <libsnapshot/snapshot.h>
#include <payload_consumer/file_descriptor.h>

namespace android::snapshot {

@@ -35,6 +36,10 @@ class SnapshotManagerStub : public ISnapshotManager {
            const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
    bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                           std::string* snapshot_path) override;
    std::unique_ptr<ICowWriter> OpenSnapshotWriter(const std::string& partition_name,
                                                   std::chrono::milliseconds timeout_ms) override;
    std::unique_ptr<FileDescriptor> OpenSnapshotReader(
            const std::string& partition_name, std::chrono::milliseconds timeout_ms = {}) override;
    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
    bool NeedSnapshotsInFirstStageMount() override;
    bool CreateLogicalAndSnapshotPartitions(
+34 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
@@ -68,6 +69,7 @@ using android::fs_mgr::SlotNumberForSlotSuffix;
using android::hardware::boot::V1_1::MergeStatus;
using chromeos_update_engine::DeltaArchiveManifest;
using chromeos_update_engine::Extent;
using chromeos_update_engine::FileDescriptor;
using chromeos_update_engine::InstallOperation;
template <typename T>
using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>;
@@ -103,6 +105,10 @@ SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
    metadata_dir_ = device_->GetMetadataDir();
}

static inline bool IsCompressionEnabled() {
    return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
}

static std::string GetCowName(const std::string& snapshot_name) {
    return snapshot_name + "-cow";
}
@@ -2420,6 +2426,11 @@ Return SnapshotManager::InitializeUpdateSnapshots(

bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                                        std::string* snapshot_path) {
    if (IsCompressionEnabled()) {
        LOG(ERROR) << "MapUpdateSnapshot cannot be used in compression mode.";
        return false;
    }

    auto lock = LockShared();
    if (!lock) return false;
    if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
@@ -2430,6 +2441,29 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para
    return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
}

std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
        const std::string& partition_name, std::chrono::milliseconds timeout_ms) {
    if (!IsCompressionEnabled()) {
        LOG(ERROR) << "OpenSnapshotWriter can only be called in compression mode.";
        return nullptr;
    }

    (void)partition_name;
    (void)timeout_ms;

    // Not yet implemented.
    return nullptr;
}

std::unique_ptr<FileDescriptor> SnapshotManager::OpenSnapshotReader(
        const std::string& partition_name, std::chrono::milliseconds timeout_ms) {
    (void)partition_name;
    (void)timeout_ms;

    // Not yet implemented.
    return nullptr;
}

bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
    auto lock = LockShared();
    if (!lock) return false;
Loading