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

Commit 36749bd6 authored by Yifan Hong's avatar Yifan Hong Committed by Gerrit Code Review
Browse files

Merge "Convert SnapshotStatus to proto"

parents 58ae8d47 5fcc2b5d
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -49,11 +49,17 @@ cc_defaults {
        "libfiemap_headers",
    ],
    export_include_dirs: ["include"],
    proto: {
        type: "lite",
        export_proto_headers: true,
        canonical_path_from_root: false,
    },
}

filegroup {
    name: "libsnapshot_sources",
    srcs: [
        "android/snapshot/snapshot.proto",
        "snapshot.cpp",
        "snapshot_metadata_updater.cpp",
        "partition_cow_creator.cpp",
@@ -132,9 +138,10 @@ cc_binary {
        "libbinder",
        "libext4_utils",
        "libfs_mgr",
        "libutils",
        "liblog",
        "liblp",
        "libprotobuf-cpp-lite",
        "libutils",
    ],
    init_rc: [
        "snapshotctl.rc",
+87 −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.

syntax = "proto3";
package android.snapshot;

option optimize_for = LITE_RUNTIME;

// Next: 4
enum SnapshotState {
    // No snapshot is found.
    NONE = 0;

    // The snapshot has been created and possibly written to. Rollbacks are
    // possible by destroying the snapshot.
    CREATED = 1;

    // Changes are being merged. No rollbacks are possible beyond this point.
    MERGING = 2;

    // Changes have been merged, Future reboots may map the base device
    // directly.
    MERGE_COMPLETED = 3;
}

// Next: 9
message SnapshotStatus {
    // Name of the snapshot. This is usually the name of the snapshotted
    // logical partition; for example, "system_b".
    string name = 1;

    SnapshotState state = 2;

    // Size of the full (base) device.
    uint64 device_size = 3;

    // Size of the snapshot. This is the sum of lengths of ranges in the base
    // device that needs to be snapshotted during the update.
    // This must be less than or equal to |device_size|.
    // This value is 0 if no snapshot is needed for this device because
    // no changes
    uint64 snapshot_size = 4;

    // Size of the "COW partition". A COW partition is a special logical
    // partition represented in the super partition metadata. This partition and
    // the "COW image" form the "COW device" that supports the snapshot device.
    //
    // When SnapshotManager creates a COW device, it first searches for unused
    // blocks in the super partition, and use those before creating the COW
    // image if the COW partition is not big enough.
    //
    // This value is 0 if no space in super is left for the COW partition.
    // |cow_partition_size + cow_file_size| must not be zero if |snapshot_size|
    // is non-zero.
    uint64 cow_partition_size = 5;

    // Size of the "COW file", or "COW image". A COW file / image is created
    // when the "COW partition" is not big enough to store changes to the
    // snapshot device.
    //
    // This value is 0 if |cow_partition_size| is big enough to hold all changes
    // to the snapshot device.
    uint64 cow_file_size = 6;

    // Sectors allocated for the COW device. Recording this value right after
    // the update and before the merge allows us to infer the progress of the
    // merge process.
    // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
    uint64 sectors_allocated = 7;

    // Metadata sectors allocated for the COW device. Recording this value right
    // before the update and before the merge allows us to infer the progress of
    // the merge process.
    // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
    uint64 metadata_sectors = 8;
}
+4 −20
Original line number Diff line number Diff line
@@ -53,8 +53,9 @@ namespace snapshot {

struct AutoDeleteCowImage;
struct AutoDeleteSnapshot;
struct PartitionCowCreator;
struct AutoDeviceList;
struct PartitionCowCreator;
class SnapshotStatus;

static constexpr const std::string_view kCowGroupName = "cow";

@@ -250,22 +251,6 @@ class SnapshotManager final {
    std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags);
    bool Truncate(LockedFile* file);

    enum class SnapshotState : int { None, Created, Merging, MergeCompleted };
    static std::string to_string(SnapshotState state);

    // This state is persisted per-snapshot in /metadata/ota/snapshots/.
    struct SnapshotStatus {
        SnapshotState state = SnapshotState::None;
        uint64_t device_size = 0;
        uint64_t snapshot_size = 0;
        uint64_t cow_partition_size = 0;
        uint64_t cow_file_size = 0;

        // These are non-zero when merging.
        uint64_t sectors_allocated = 0;
        uint64_t metadata_sectors = 0;
    };

    // Create a new snapshot record. This creates the backing COW store and
    // persists information needed to map the device. The device can be mapped
    // with MapSnapshot().
@@ -282,7 +267,7 @@ class SnapshotManager final {
    //
    // All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes
    // must be a multiple of the sector size (512 bytes).
    bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status);
    bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status);

    // |name| should be the base partition name (e.g. "system_a"). Create the
    // backing COW image using the size previously passed to CreateSnapshot().
@@ -363,8 +348,7 @@ class SnapshotManager final {
    UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);

    // Interact with status files under /metadata/ota/snapshots.
    bool WriteSnapshotStatus(LockedFile* lock, const std::string& name,
                             const SnapshotStatus& status);
    bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status);
    bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
    std::string GetSnapshotStatusFilePath(const std::string& name);

+12 −8
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <android-base/logging.h>

#include <android/snapshot/snapshot.pb.h>
#include "utility.h"

using android::dm::kSectorSize;
@@ -84,13 +85,14 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() {
            << "logical_block_size is not power of 2";

    Return ret;
    ret.snapshot_status.device_size = target_partition->size();
    ret.snapshot_status.set_name(target_partition->name());
    ret.snapshot_status.set_device_size(target_partition->size());

    // TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition
    // may be written directly.
    ret.snapshot_status.snapshot_size = target_partition->size();
    ret.snapshot_status.set_snapshot_size(target_partition->size());

    auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size);
    auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size());
    if (!cow_size.has_value()) return std::nullopt;

    // Compute regions that are free in both current and target metadata. These are the regions
@@ -106,18 +108,20 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() {
    LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes";

    // Compute the COW partition size.
    ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length);
    uint64_t cow_partition_size = std::min(*cow_size, free_region_length);
    // Round it down to the nearest logical block. Logical partitions must be a multiple
    // of logical blocks.
    ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1);
    cow_partition_size &= ~(logical_block_size - 1);
    ret.snapshot_status.set_cow_partition_size(cow_partition_size);
    // Assign cow_partition_usable_regions to indicate what regions should the COW partition uses.
    ret.cow_partition_usable_regions = std::move(free_regions);

    // The rest of the COW space is allocated on ImageManager.
    ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size;
    uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size();
    // Round it up to the nearest sector.
    ret.snapshot_status.cow_file_size += kSectorSize - 1;
    ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1);
    cow_file_size += kSectorSize - 1;
    cow_file_size &= ~(kSectorSize - 1);
    ret.snapshot_status.set_cow_file_size(cow_file_size);

    return ret;
}
+3 −2
Original line number Diff line number Diff line
@@ -20,8 +20,9 @@
#include <string>

#include <liblp/builder.h>
#include <update_engine/update_metadata.pb.h>

#include <libsnapshot/snapshot.h>
#include <android/snapshot/snapshot.pb.h>

namespace android {
namespace snapshot {
@@ -51,7 +52,7 @@ struct PartitionCowCreator {
    const RepeatedPtrField<InstallOperation>* operations = nullptr;

    struct Return {
        SnapshotManager::SnapshotStatus snapshot_status;
        SnapshotStatus snapshot_status;
        std::vector<Interval> cow_partition_usable_regions;
    };

Loading