Merge "Change HardcodedFlash to add flashtasks"
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index e931bec..9d1ce7d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -85,11 +85,9 @@
"android/snapshot/snapshot.proto",
"device_info.cpp",
"snapshot.cpp",
- "snapshot_reader.cpp",
"snapshot_stats.cpp",
"snapshot_stub.cpp",
"snapshot_metadata_updater.cpp",
- "snapshot_writer.cpp",
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
@@ -165,6 +163,9 @@
"liblz4",
"libzstd",
],
+ header_libs: [
+ "libupdate_engine_headers",
+ ],
export_include_dirs: ["include"],
}
@@ -179,6 +180,7 @@
"libsnapshot_cow/cow_format.cpp",
"libsnapshot_cow/cow_reader.cpp",
"libsnapshot_cow/parser_v2.cpp",
+ "libsnapshot_cow/snapshot_reader.cpp",
"libsnapshot_cow/writer_base.cpp",
"libsnapshot_cow/writer_v2.cpp",
],
@@ -224,9 +226,7 @@
srcs: [
"partition_cow_creator_test.cpp",
"snapshot_metadata_updater_test.cpp",
- "snapshot_reader_test.cpp",
"snapshot_test.cpp",
- "snapshot_writer_test.cpp",
],
shared_libs: [
"libbinder",
@@ -372,6 +372,7 @@
"libsnapshot_cow_defaults",
],
srcs: [
+ "libsnapshot_cow/snapshot_reader_test.cpp",
"libsnapshot_cow/test_v2.cpp",
],
cflags: [
@@ -416,6 +417,7 @@
"libbrotli",
"libcrypto_static",
"liblog",
+ "libgflags",
"libsnapshot_cow",
"libz",
],
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 95a1270..3890b17 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -24,6 +24,10 @@
#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>
+namespace chromeos_update_engine {
+class FileDescriptor;
+} // namespace chromeos_update_engine
+
namespace android {
namespace snapshot {
@@ -32,6 +36,8 @@
// Interface for reading from a snapuserd COW.
class ICowReader {
public:
+ using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
virtual ~ICowReader() {}
// Return the file header.
@@ -109,10 +115,9 @@
bool Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label = {});
bool InitForMerge(android::base::unique_fd&& fd);
+
bool VerifyMergeOps() override;
-
bool GetFooter(CowFooter* footer) override;
-
bool GetLastLabel(uint64_t* label) override;
// Create a CowOpIter object which contains footer_.num_ops
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index af2d3ef..d6194eb 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -61,6 +61,8 @@
// will occur in the sequence they were added to the COW.
class ICowWriter {
public:
+ using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
virtual ~ICowWriter() {}
// Encode an operation that copies the contents of |old_block| to the
@@ -93,6 +95,17 @@
virtual uint32_t GetBlockSize() const = 0;
virtual std::optional<uint32_t> GetMaxBlocks() const = 0;
+
+ // Open an ICowReader for this writer. The reader will be a snapshot of the
+ // current operations in the writer; new writes after OpenReader() will not
+ // be reflected.
+ virtual std::unique_ptr<ICowReader> OpenReader() = 0;
+
+ // Open a file descriptor. This allows reading and seeing through the cow
+ // as if it were a normal file. The optional source_device must be a valid
+ // path if the CowReader contains any copy or xor operations.
+ virtual std::unique_ptr<FileDescriptor> OpenFileDescriptor(
+ const std::optional<std::string>& source_device) = 0;
};
class CompressWorker {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
similarity index 75%
rename from fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
rename to fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
index 52e3a9c..c58c654 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_cow_writer.h
@@ -15,17 +15,16 @@
//
#include <gmock/gmock.h>
-#include <libsnapshot/snapshot_writer.h>
+#include <libsnapshot/cow_writer.h>
namespace android::snapshot {
-class MockSnapshotWriter : public ISnapshotWriter {
+class MockCowWriter : public ICowWriter {
public:
- using FileDescriptor = ISnapshotWriter::FileDescriptor;
+ using FileDescriptor = chromeos_update_engine::FileDescriptor;
MOCK_METHOD(bool, Finalize, (), (override));
- // Return number of bytes the cow image occupies on disk.
MOCK_METHOD(uint64_t, GetCowSize, (), (override));
MOCK_METHOD(bool, AddCopy, (uint64_t, uint64_t, uint64_t), (override));
@@ -35,11 +34,12 @@
MOCK_METHOD(bool, AddZeroBlocks, (uint64_t, uint64_t), (override));
MOCK_METHOD(bool, AddLabel, (uint64_t), (override));
MOCK_METHOD(bool, AddSequenceData, (size_t, const uint32_t*), (override));
- MOCK_METHOD(bool, Initialize, (), (override));
- MOCK_METHOD(bool, InitializeAppend, (uint64_t), (override));
- MOCK_METHOD(bool, VerifyMergeOps, (), (override, const, noexcept));
- MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenReader, (), (override));
MOCK_METHOD(uint32_t, GetBlockSize, (), (override, const));
MOCK_METHOD(std::optional<uint32_t>, GetMaxBlocks, (), (override, const));
+
+ MOCK_METHOD(std::unique_ptr<ICowReader>, OpenReader, (), (override));
+ MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenFileDescriptor,
+ (const std::optional<std::string>&), (override));
};
+
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index d458b87..ca45d2f 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -42,9 +42,9 @@
(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path),
(override));
- MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
+ MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
(const android::fs_mgr::CreateLogicalPartitionParams& params,
- const std::optional<std::string>&),
+ std::optional<uint64_t>),
(override));
MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index ecf1d15..df532ee 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -33,12 +33,11 @@
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
-#include <update_engine/update_metadata.pb.h>
-
#include <libsnapshot/auto_device.h>
+#include <libsnapshot/cow_writer.h>
#include <libsnapshot/return.h>
-#include <libsnapshot/snapshot_writer.h>
#include <snapuserd/snapuserd_client.h>
+#include <update_engine/update_metadata.pb.h>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@@ -211,16 +210,13 @@
virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) = 0;
- // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
+ // Create an ICowWriter to build a snapshot against a target partition. The partition name
// must be suffixed. If a source partition exists, it must be specified as well. The source
// partition will only be used if raw bytes are needed. The source partition should be an
// absolute path to the device, not a partition name.
- //
- // After calling OpenSnapshotWriter, the caller must invoke Initialize or InitializeForAppend
- // before invoking write operations.
- virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params,
- const std::optional<std::string>& source_device) = 0;
+ std::optional<uint64_t> label = {}) = 0;
// Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
// OpenSnapshotWriter. All outstanding open descriptors, writers, or
@@ -362,9 +358,9 @@
Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
- std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params,
- const std::optional<std::string>& source_device) override;
+ std::optional<uint64_t> label) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
bool CreateLogicalAndSnapshotPartitions(
@@ -693,10 +689,10 @@
};
// Helpers for OpenSnapshotWriter.
- std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(
- LockedFile* lock, const std::optional<std::string>& source_device,
- const std::string& partition_name, const SnapshotStatus& status,
- const SnapshotPaths& paths);
+ std::unique_ptr<ICowWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
+ const SnapshotStatus& status,
+ const SnapshotPaths& paths,
+ std::optional<uint64_t> label);
// Map the base device, COW devices, and snapshot device.
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
@@ -743,7 +739,7 @@
// Initialize snapshots so that they can be mapped later.
// Map the COW partition and zero-initialize the header.
Return InitializeUpdateSnapshots(
- LockedFile* lock, MetadataBuilder* target_metadata,
+ LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
const std::map<std::string, SnapshotStatus>& all_snapshot_status);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 171c7c6..1c9b403 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -40,9 +40,9 @@
const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
- std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params,
- const std::optional<std::string>& source_device) override;
+ std::optional<uint64_t> label) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
bool CreateLogicalAndSnapshotPartitions(
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
deleted file mode 100644
index 2653a60..0000000
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2020 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 <optional>
-
-#include <android-base/unique_fd.h>
-
-#include <libsnapshot/cow_writer.h>
-
-namespace chromeos_update_engine {
-class FileDescriptor;
-} // namespace chromeos_update_engine
-
-namespace android {
-namespace snapshot {
-
-class ISnapshotWriter : public ICowWriter {
- public:
- using FileDescriptor = chromeos_update_engine::FileDescriptor;
-
- virtual ~ISnapshotWriter() {}
-
- // Open the writer in write mode (no append).
- virtual bool Initialize() = 0;
-
- // Open the writer in append mode, with the last label to resume
- // from. See CowWriter::InitializeAppend.
- virtual bool InitializeAppend(uint64_t label) = 0;
-
- virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
-
- virtual bool VerifyMergeOps() const noexcept = 0;
-};
-
-// Send writes to a COW or a raw device directly, based on a threshold.
-class CompressedSnapshotWriter final : public ISnapshotWriter {
- public:
- CompressedSnapshotWriter(const CowOptions& options);
-
- void SetSourceDevice(const std::string& source_device);
-
- // Sets the COW device; this is required.
- bool SetCowDevice(android::base::unique_fd&& cow_device);
-
- bool Initialize() override;
- bool InitializeAppend(uint64_t label) override;
- bool Finalize() override;
- uint64_t GetCowSize() override;
- uint32_t GetBlockSize() const override;
- std::optional<uint32_t> GetMaxBlocks() const override;
- std::unique_ptr<FileDescriptor> OpenReader() override;
- bool VerifyMergeOps() const noexcept;
-
- bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
- bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
- bool AddXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
- uint16_t offset) override;
- bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
- bool AddLabel(uint64_t label) override;
- bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
-
- private:
- std::unique_ptr<CowReader> OpenCowReader() const;
- android::base::borrowed_fd GetSourceFd();
-
- CowOptions options_;
-
- // Set the source device. This is used for AddCopy() operations, if the
- // underlying writer needs the original bytes (for example if backed by
- // dm-snapshot or if writing directly to an unsnapshotted region). The
- // device is only opened on the first operation that requires it.
- std::optional<std::string> source_device_;
- android::base::unique_fd source_fd_;
-
- android::base::unique_fd cow_device_;
- std::unique_ptr<ICowWriter> cow_;
-};
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index f45d4ed..5e9f049 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -198,7 +198,7 @@
// Expect space of |path| is multiple of 4K.
bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
std::string* hash = nullptr);
-std::string HashSnapshot(ISnapshotWriter* writer);
+std::string HashSnapshot(ICowWriter::FileDescriptor* writer);
std::string ToHexString(const uint8_t* buf, size_t len);
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
index c2c86ee..148ecb0 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
@@ -24,11 +24,26 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <gflags/gflags.h>
#include <libsnapshot/cow_reader.h>
+#include "parser_v2.h"
+
+DEFINE_bool(silent, false, "Run silently");
+DEFINE_bool(decompress, false, "Attempt to decompress data ops");
+DEFINE_bool(show_bad_data, false, "If an op fails to decompress, show its daw data");
+DEFINE_bool(show_ops, false, "Print all opcode information");
+DEFINE_string(order, "", "If show_ops is true, change the order (either merge or reverse-merge)");
+DEFINE_bool(show_merged, false,
+ "If show_ops is true, and order is merge or reverse-merge, include merged ops");
+DEFINE_bool(verify_merge_sequence, false, "Verify merge order sequencing");
+DEFINE_bool(show_merge_sequence, false, "Show merge order sequence");
+DEFINE_bool(show_raw_ops, false, "Show raw ops directly from the underlying parser");
namespace android {
namespace snapshot {
+using android::base::borrowed_fd;
+
void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
unsigned int, const char* message) {
if (severity == android::base::ERROR) {
@@ -38,32 +53,6 @@
}
}
-static void usage(void) {
- std::cerr << "Usage: inspect_cow [-sd] <COW_FILE>\n";
- std::cerr << "\t -s Run Silent\n";
- std::cerr << "\t -d Attempt to decompress\n";
- std::cerr << "\t -b Show data for failed decompress\n";
- std::cerr << "\t -l Show ops\n";
- std::cerr << "\t -m Show ops in reverse merge order\n";
- std::cerr << "\t -n Show ops in merge order\n";
- std::cerr << "\t -a Include merged ops in any merge order listing\n";
- std::cerr << "\t -o Shows sequence op block order\n";
- std::cerr << "\t -v Verifies merge order has no conflicts\n";
-}
-
-enum OpIter { Normal, RevMerge, Merge };
-
-struct Options {
- bool silent;
- bool decompress;
- bool show_ops;
- bool show_bad;
- bool show_seq;
- bool verify_sequence;
- OpIter iter_type;
- bool include_merged;
-};
-
static void ShowBad(CowReader& reader, const struct CowOperation* op) {
size_t count;
auto buffer = std::make_unique<uint8_t[]>(op->data_length);
@@ -82,7 +71,39 @@
}
}
-static bool Inspect(const std::string& path, Options opt) {
+static bool ShowRawOpStreamV2(borrowed_fd fd, const CowHeader& header) {
+ CowParserV2 parser;
+ if (!parser.Parse(fd, header)) {
+ LOG(ERROR) << "v2 parser failed";
+ return false;
+ }
+ for (const auto& op : *parser.ops()) {
+ std::cout << op << "\n";
+ if (auto iter = parser.data_loc()->find(op.new_block); iter != parser.data_loc()->end()) {
+ std::cout << " data loc: " << iter->second << "\n";
+ }
+ }
+ return true;
+}
+
+static bool ShowRawOpStream(borrowed_fd fd) {
+ CowHeader header;
+ if (!ReadCowHeader(fd, &header)) {
+ LOG(ERROR) << "parse header failed";
+ return false;
+ }
+
+ switch (header.prefix.major_version) {
+ case 1:
+ case 2:
+ return ShowRawOpStreamV2(fd, header);
+ default:
+ LOG(ERROR) << "unknown COW version: " << header.prefix.major_version;
+ return false;
+ }
+}
+
+static bool Inspect(const std::string& path) {
android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
if (fd < 0) {
PLOG(ERROR) << "open failed: " << path;
@@ -103,7 +124,7 @@
bool has_footer = false;
if (reader.GetFooter(&footer)) has_footer = true;
- if (!opt.silent) {
+ if (!FLAGS_silent) {
std::cout << "Version: " << header.prefix.major_version << "."
<< header.prefix.minor_version << "\n";
std::cout << "Header size: " << header.prefix.header_size << "\n";
@@ -119,11 +140,11 @@
}
}
- if (!opt.silent) {
+ if (!FLAGS_silent) {
std::cout << "Parse time: " << (parse_time.count() * 1000) << "ms\n";
}
- if (opt.verify_sequence) {
+ if (FLAGS_verify_merge_sequence) {
std::cout << "\n";
if (reader.VerifyMergeOps()) {
std::cout << "\nMerge sequence is consistent.\n";
@@ -133,32 +154,47 @@
}
std::unique_ptr<ICowOpIter> iter;
- if (opt.iter_type == Normal) {
+ if (FLAGS_order.empty()) {
iter = reader.GetOpIter();
- } else if (opt.iter_type == RevMerge) {
- iter = reader.GetRevMergeOpIter(opt.include_merged);
- } else if (opt.iter_type == Merge) {
- iter = reader.GetMergeOpIter(opt.include_merged);
+ } else if (FLAGS_order == "reverse-merge") {
+ iter = reader.GetRevMergeOpIter(FLAGS_show_merged);
+ } else if (FLAGS_order == "merge") {
+ iter = reader.GetMergeOpIter(FLAGS_show_merged);
}
std::string buffer(header.block_size, '\0');
+ if (!FLAGS_silent && FLAGS_show_raw_ops) {
+ std::cout << "\n";
+ std::cout << "Listing raw op stream:\n";
+ std::cout << "----------------------\n";
+ if (!ShowRawOpStream(fd)) {
+ return false;
+ }
+ }
+
+ if (!FLAGS_silent && FLAGS_show_ops) {
+ std::cout << "\n";
+ std::cout << "Listing op stream:\n";
+ std::cout << "------------------\n";
+ }
+
bool success = true;
uint64_t xor_ops = 0, copy_ops = 0, replace_ops = 0, zero_ops = 0;
while (!iter->AtEnd()) {
const CowOperation* op = iter->Get();
- if (!opt.silent && opt.show_ops) std::cout << *op << "\n";
+ if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n";
- if (opt.decompress && op->type == kCowReplaceOp && op->compression != kCowCompressNone) {
+ if (FLAGS_decompress && op->type == kCowReplaceOp && op->compression != kCowCompressNone) {
if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) {
std::cerr << "Failed to decompress for :" << *op << "\n";
success = false;
- if (opt.show_bad) ShowBad(reader, op);
+ if (FLAGS_show_bad_data) ShowBad(reader, op);
}
}
- if (op->type == kCowSequenceOp && opt.show_seq) {
+ if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) {
size_t read;
std::vector<uint32_t> merge_op_blocks;
size_t seq_len = op->data_length / sizeof(uint32_t);
@@ -167,7 +203,7 @@
PLOG(ERROR) << "Failed to read sequence op!";
return false;
}
- if (!opt.silent) {
+ if (!FLAGS_silent) {
std::cout << "Sequence for " << *op << " is :\n";
for (size_t i = 0; i < seq_len; i++) {
std::cout << std::setfill('0') << std::setw(6) << merge_op_blocks[i] << ", ";
@@ -189,7 +225,7 @@
iter->Next();
}
- if (!opt.silent) {
+ if (!FLAGS_silent) {
auto total_ops = replace_ops + zero_ops + copy_ops + xor_ops;
std::cout << "Data ops: " << total_ops << "\n";
std::cout << "Replace ops: " << replace_ops << "\n";
@@ -205,57 +241,20 @@
} // namespace android
int main(int argc, char** argv) {
- int ch;
- struct android::snapshot::Options opt;
- opt.silent = false;
- opt.decompress = false;
- opt.show_bad = false;
- opt.iter_type = android::snapshot::Normal;
- opt.verify_sequence = false;
- opt.include_merged = false;
- while ((ch = getopt(argc, argv, "sdbmnolva")) != -1) {
- switch (ch) {
- case 's':
- opt.silent = true;
- break;
- case 'd':
- opt.decompress = true;
- break;
- case 'b':
- opt.show_bad = true;
- break;
- case 'm':
- opt.iter_type = android::snapshot::RevMerge;
- break;
- case 'n':
- opt.iter_type = android::snapshot::Merge;
- break;
- case 'o':
- opt.show_seq = true;
- break;
- case 'l':
- opt.show_ops = true;
- break;
- case 'v':
- opt.verify_sequence = true;
- break;
- case 'a':
- opt.include_merged = true;
- break;
- default:
- android::snapshot::usage();
- return 1;
- }
- }
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
- if (argc < optind + 1) {
- android::snapshot::usage();
+ if (argc < 2) {
+ gflags::ShowUsageWithFlags(argv[0]);
+ return 1;
+ }
+ if (FLAGS_order != "" && FLAGS_order != "merge" && FLAGS_order != "reverse-merge") {
+ std::cerr << "Order must either be \"merge\" or \"reverse-merge\".\n";
return 1;
}
android::base::InitLogging(argv, android::snapshot::MyLogger);
- if (!android::snapshot::Inspect(argv[optind], opt)) {
+ if (!android::snapshot::Inspect(argv[1])) {
return 1;
}
return 0;
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
similarity index 82%
rename from fs_mgr/libsnapshot/snapshot_reader.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
index 4e75ba7..f9cdbc0 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.cpp
@@ -18,73 +18,24 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <ext4_utils/ext4_utils.h>
namespace android {
namespace snapshot {
using android::base::borrowed_fd;
-// Not supported.
-bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
- errno = EINVAL;
- return false;
-}
-
-bool ReadOnlyFileDescriptor::Open(const char*, int) {
- errno = EINVAL;
- return false;
-}
-
-ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
- errno = EINVAL;
- return false;
-}
-
-bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
- errno = EINVAL;
- return false;
-}
-
-ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
-
-ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
- return read(fd_.get(), buf, count);
-}
-
-off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
- return lseek(fd_.get(), offset, whence);
-}
-
-uint64_t ReadFdFileDescriptor::BlockDevSize() {
- return get_block_device_size(fd_.get());
-}
-
-bool ReadFdFileDescriptor::Close() {
- fd_ = {};
- return true;
-}
-
-bool ReadFdFileDescriptor::IsSettingErrno() {
- return true;
-}
-
-bool ReadFdFileDescriptor::IsOpen() {
- return fd_ >= 0;
-}
-
-bool ReadFdFileDescriptor::Flush() {
- return true;
-}
-
-bool CompressedSnapshotReader::SetCow(std::unique_ptr<CowReader>&& cow) {
- cow_ = std::move(cow);
-
+CompressedSnapshotReader::CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
+ const std::optional<std::string>& source_device,
+ std::optional<uint64_t> block_dev_size)
+ : cow_(std::move(cow)),
+ block_size_(cow_->GetHeader().block_size),
+ source_device_(source_device),
+ block_device_size_(block_dev_size.value_or(0)) {
const auto& header = cow_->GetHeader();
block_size_ = header.block_size;
// Populate the operation map.
- op_iter_ = cow_->GetOpIter();
+ op_iter_ = cow_->GetOpIter(false);
while (!op_iter_->AtEnd()) {
const CowOperation* op = op_iter_->Get();
if (IsMetadataOp(*op)) {
@@ -97,16 +48,27 @@
ops_[op->new_block] = op;
op_iter_->Next();
}
-
- return true;
}
-void CompressedSnapshotReader::SetSourceDevice(const std::string& source_device) {
- source_device_ = {source_device};
+// Not supported.
+bool CompressedSnapshotReader::Open(const char*, int, mode_t) {
+ errno = EINVAL;
+ return false;
}
-void CompressedSnapshotReader::SetBlockDeviceSize(uint64_t block_device_size) {
- block_device_size_ = block_device_size;
+bool CompressedSnapshotReader::Open(const char*, int) {
+ errno = EINVAL;
+ return false;
+}
+
+ssize_t CompressedSnapshotReader::Write(const void*, size_t) {
+ errno = EINVAL;
+ return false;
+}
+
+bool CompressedSnapshotReader::BlkIoctl(int, uint64_t, uint64_t, int*) {
+ errno = EINVAL;
+ return false;
}
borrowed_fd CompressedSnapshotReader::GetSourceFd() {
diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
similarity index 69%
rename from fs_mgr/libsnapshot/snapshot_reader.h
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
index 5e19c62..3de63ed 100644
--- a/fs_mgr/libsnapshot/snapshot_reader.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader.h
@@ -26,36 +26,16 @@
namespace android {
namespace snapshot {
-class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
+class CompressedSnapshotReader : public chromeos_update_engine::FileDescriptor {
public:
+ CompressedSnapshotReader(std::unique_ptr<ICowReader>&& cow,
+ const std::optional<std::string>& source_device,
+ std::optional<uint64_t> block_dev_size);
+
bool Open(const char* path, int flags, mode_t mode) override;
bool Open(const char* path, int flags) override;
ssize_t Write(const void* buf, size_t count) override;
bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override;
-};
-
-class ReadFdFileDescriptor : public ReadOnlyFileDescriptor {
- public:
- explicit ReadFdFileDescriptor(android::base::unique_fd&& fd);
-
- ssize_t Read(void* buf, size_t count) override;
- off64_t Seek(off64_t offset, int whence) override;
- uint64_t BlockDevSize() override;
- bool Close() override;
- bool IsSettingErrno() override;
- bool IsOpen() override;
- bool Flush() override;
-
- private:
- android::base::unique_fd fd_;
-};
-
-class CompressedSnapshotReader : public ReadOnlyFileDescriptor {
- public:
- bool SetCow(std::unique_ptr<CowReader>&& cow);
- void SetSourceDevice(const std::string& source_device);
- void SetBlockDeviceSize(uint64_t block_device_size);
-
ssize_t Read(void* buf, size_t count) override;
off64_t Seek(off64_t offset, int whence) override;
uint64_t BlockDevSize() override;
@@ -68,7 +48,7 @@
ssize_t ReadBlock(uint64_t chunk, size_t start_offset, void* buffer, size_t size);
android::base::borrowed_fd GetSourceFd();
- std::unique_ptr<CowReader> cow_;
+ std::unique_ptr<ICowReader> cow_;
std::unique_ptr<ICowOpIter> op_iter_;
uint32_t block_size_ = 0;
diff --git a/fs_mgr/libsnapshot/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
similarity index 92%
rename from fs_mgr/libsnapshot/snapshot_reader_test.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
index f25023d..10cb06d 100644
--- a/fs_mgr/libsnapshot/snapshot_reader_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <libsnapshot/snapshot.h>
-
#include <unordered_set>
#include <android-base/file.h>
@@ -61,7 +59,7 @@
ASSERT_EQ(fsync(base_->fd), 0);
}
- void WriteCow(ISnapshotWriter* writer) {
+ void WriteCow(ICowWriter* writer) {
std::string new_block = MakeNewBlockString();
std::string xor_block = MakeXorBlockString();
@@ -72,8 +70,8 @@
ASSERT_TRUE(writer->Finalize());
}
- void TestBlockReads(ISnapshotWriter* writer) {
- auto reader = writer->OpenReader();
+ void TestBlockReads(ICowWriter* writer) {
+ auto reader = writer->OpenFileDescriptor(base_->path);
ASSERT_NE(reader, nullptr);
// Test that unchanged blocks are not modified.
@@ -117,8 +115,8 @@
ASSERT_EQ(two_blocks, zeroes);
}
- void TestByteReads(ISnapshotWriter* writer) {
- auto reader = writer->OpenReader();
+ void TestByteReads(ICowWriter* writer) {
+ auto reader = writer->OpenFileDescriptor(base_->path);
ASSERT_NE(reader, nullptr);
std::string blob(kBlockSize * 3, 'x');
@@ -154,7 +152,7 @@
ASSERT_EQ(got, expected);
}
- void TestReads(ISnapshotWriter* writer) {
+ void TestReads(ICowWriter* writer) {
ASSERT_NO_FATAL_FAILURE(TestBlockReads(writer));
ASSERT_NO_FATAL_FAILURE(TestByteReads(writer));
}
@@ -186,10 +184,7 @@
unique_fd cow_fd(dup(cow_->fd));
ASSERT_GE(cow_fd, 0);
- auto writer = std::make_unique<CompressedSnapshotWriter>(options);
- writer->SetSourceDevice(base_->path);
- ASSERT_TRUE(writer->SetCowDevice(std::move(cow_fd)));
- ASSERT_TRUE(writer->Initialize());
+ auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd));
ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get()));
ASSERT_NO_FATAL_FAILURE(TestReads(writer.get()));
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
index 22e63d0..ff34c59 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.cpp
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <android-base/logging.h>
+#include "snapshot_reader.h"
// The info messages here are spammy, but as useful for update_engine. Disable
// them when running on the host.
@@ -159,5 +160,36 @@
return true;
}
+std::unique_ptr<ICowReader> CowWriterBase::OpenReader() {
+ unique_fd cow_fd(fcntl(fd_.get(), F_DUPFD | F_DUPFD_CLOEXEC, 0));
+ if (cow_fd < 0) {
+ PLOG(ERROR) << "CowWriterV2::OpenReander: dup COW device";
+ return nullptr;
+ }
+
+ auto cow = std::make_unique<CowReader>();
+ if (!cow->Parse(std::move(cow_fd))) {
+ LOG(ERROR) << "CowWriterV2::OpenReader: unable to read COW";
+ return nullptr;
+ }
+ return cow;
+}
+
+std::unique_ptr<chromeos_update_engine::FileDescriptor> CowWriterBase::OpenFileDescriptor(
+ const std::optional<std::string>& source_device) {
+ auto reader = OpenReader();
+ if (!reader) {
+ return nullptr;
+ }
+
+ std::optional<uint64_t> block_dev_size;
+ if (options_.max_blocks) {
+ block_dev_size = {*options_.max_blocks * options_.block_size};
+ }
+
+ return std::make_unique<CompressedSnapshotReader>(std::move(reader), source_device,
+ block_dev_size);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
index 8fa9065..c8b4772 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h
@@ -43,6 +43,9 @@
bool AddSequenceData(size_t num_ops, const uint32_t* data) override;
uint32_t GetBlockSize() const override { return options_.block_size; }
std::optional<uint32_t> GetMaxBlocks() const override { return options_.max_blocks; }
+ std::unique_ptr<ICowReader> OpenReader() override;
+ std::unique_ptr<FileDescriptor> OpenFileDescriptor(
+ const std::optional<std::string>& source_device) override;
const CowOptions& options() const { return options_; }
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
index b6603da..c549969 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v2.cpp
@@ -14,6 +14,8 @@
// limitations under the License.
//
+#include "writer_v2.h"
+
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
@@ -37,7 +39,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
-#include "writer_v2.h"
+#include "parser_v2.h"
// The info messages here are spammy, but as useful for update_engine. Disable
// them when running on the host.
@@ -252,14 +254,20 @@
}
bool CowWriterV2::OpenForAppend(uint64_t label) {
- auto reader = std::make_unique<CowReader>();
- std::queue<CowOperation> toAdd;
-
- if (!reader->Parse(fd_, {label})) {
+ if (!ReadCowHeader(fd_, &header_)) {
return false;
}
- header_ = reader->GetHeader();
+ CowParserV2 parser;
+ if (!parser.Parse(fd_, header_, {label})) {
+ return false;
+ }
+ if (header_.prefix.major_version > 2) {
+ LOG(ERROR) << "CowWriterV2 tried to open incompatible version "
+ << header_.prefix.major_version;
+ return false;
+ }
+
options_.block_size = header_.block_size;
options_.cluster_ops = header_.cluster_ops;
@@ -267,16 +275,10 @@
footer_.op.num_ops = 0;
InitPos();
- auto iter = reader->GetOpIter();
-
- while (!iter->AtEnd()) {
- AddOperation(*iter->Get());
- iter->Next();
+ for (const auto& op : *parser.ops()) {
+ AddOperation(op);
}
- // Free reader so we own the descriptor position again.
- reader = nullptr;
-
if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
PLOG(ERROR) << "lseek failed";
return false;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 5920bc2..fbea79b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -45,10 +45,9 @@
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
-#include "libsnapshot_cow/writer_v2.h"
+#include "libsnapshot_cow/parser_v2.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
-#include "snapshot_reader.h"
#include "utility.h"
namespace android {
@@ -3288,7 +3287,7 @@
return Return::Error();
}
- ret = InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
+ ret = InitializeUpdateSnapshots(lock.get(), dap_metadata.cow_version(), target_metadata.get(),
exported_target_metadata.get(), target_suffix,
all_snapshot_status);
if (!ret.is_ok()) return ret;
@@ -3510,7 +3509,7 @@
}
Return SnapshotManager::InitializeUpdateSnapshots(
- LockedFile* lock, MetadataBuilder* target_metadata,
+ LockedFile* lock, uint32_t cow_version, MetadataBuilder* target_metadata,
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
CHECK(lock);
@@ -3558,8 +3557,8 @@
}
options.compression = it->second.compression_algorithm();
- CowWriterV2 writer(options, std::move(fd));
- if (!writer.Initialize(std::nullopt) || !writer.Finalize()) {
+ auto writer = CreateCowWriter(cow_version, options, std::move(fd));
+ if (!writer->Finalize()) {
LOG(ERROR) << "Could not initialize COW device for " << target_partition->name();
return Return::Error();
}
@@ -3609,12 +3608,12 @@
return true;
}
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
+std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params,
- const std::optional<std::string>& source_device) {
+ std::optional<uint64_t> label) {
#if defined(LIBSNAPSHOT_NO_COW_WRITE)
(void)params;
- (void)source_device;
+ (void)label;
LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
return nullptr;
@@ -3653,16 +3652,14 @@
return nullptr;
}
- return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
- status, paths);
+ return OpenCompressedSnapshotWriter(lock.get(), status, paths, label);
#endif
}
#if !defined(LIBSNAPSHOT_NO_COW_WRITE)
-std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
- LockedFile* lock, const std::optional<std::string>& source_device,
- [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status,
- const SnapshotPaths& paths) {
+std::unique_ptr<ICowWriter> SnapshotManager::OpenCompressedSnapshotWriter(
+ LockedFile* lock, const SnapshotStatus& status, const SnapshotPaths& paths,
+ std::optional<uint64_t> label) {
CHECK(lock);
CowOptions cow_options;
@@ -3679,11 +3676,6 @@
// never creates this scenario.
CHECK(status.snapshot_size() == status.device_size());
- auto writer = std::make_unique<CompressedSnapshotWriter>(cow_options);
- if (source_device) {
- writer->SetSourceDevice(*source_device);
- }
-
std::string cow_path;
if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
LOG(ERROR) << "Could not determine path for " << paths.cow_device_name;
@@ -3695,12 +3687,14 @@
PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path;
return nullptr;
}
- if (!writer->SetCowDevice(std::move(cow_fd))) {
- LOG(ERROR) << "Could not create COW writer from " << cow_path;
+
+ CowHeader header;
+ if (!ReadCowHeader(cow_fd, &header)) {
+ LOG(ERROR) << "OpenCompressedSnapshotWriter: read header failed";
return nullptr;
}
- return writer;
+ return CreateCowWriter(header.prefix.major_version, cow_options, std::move(cow_fd), label);
}
#endif // !defined(LIBSNAPSHOT_NO_COW_WRITE)
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 84e2226..9354102 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -154,8 +154,8 @@
return &snapshot_merge_stats;
}
-std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
- const CreateLogicalPartitionParams&, const std::optional<std::string>&) {
+std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(
+ const CreateLogicalPartitionParams&, std::optional<uint64_t>) {
LOG(ERROR) << __FUNCTION__ << " should never be called.";
return nullptr;
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index dac1b77..0a85489 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -345,7 +345,7 @@
}
AssertionResult MapUpdateSnapshot(const std::string& name,
- std::unique_ptr<ISnapshotWriter>* writer) {
+ std::unique_ptr<ICowWriter>* writer) {
TestPartitionOpener opener(fake_super);
CreateLogicalPartitionParams params{
.block_device = fake_super,
@@ -355,14 +355,10 @@
.partition_opener = &opener,
};
- auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
- auto result = sm->OpenSnapshotWriter(params, {old_partition});
+ auto result = sm->OpenSnapshotWriter(params, {});
if (!result) {
return AssertionFailure() << "Cannot open snapshot for writing: " << name;
}
- if (!result->Initialize()) {
- return AssertionFailure() << "Cannot initialize snapshot for writing: " << name;
- }
if (writer) {
*writer = std::move(result);
@@ -440,7 +436,7 @@
// Prepare A/B slot for a partition named "test_partition".
AssertionResult PrepareOneSnapshot(uint64_t device_size,
- std::unique_ptr<ISnapshotWriter>* writer = nullptr) {
+ std::unique_ptr<ICowWriter>* writer = nullptr) {
lock_ = nullptr;
DeltaArchiveManifest manifest;
@@ -651,7 +647,7 @@
bool userspace_snapshots = false;
if (snapuserd_required_) {
- std::unique_ptr<ISnapshotWriter> writer;
+ std::unique_ptr<ICowWriter> writer;
ASSERT_TRUE(PrepareOneSnapshot(kDeviceSize, &writer));
userspace_snapshots = sm->UpdateUsesUserSnapshots(lock_.get());
@@ -1160,7 +1156,7 @@
AssertionResult MapOneUpdateSnapshot(const std::string& name) {
if (snapuserd_required_) {
- std::unique_ptr<ISnapshotWriter> writer;
+ std::unique_ptr<ICowWriter> writer;
return MapUpdateSnapshot(name, &writer);
} else {
std::string path;
@@ -1181,7 +1177,7 @@
AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
std::string name = partition->partition_name() + "_b";
if (snapuserd_required_) {
- std::unique_ptr<ISnapshotWriter> writer;
+ std::unique_ptr<ICowWriter> writer;
auto res = MapUpdateSnapshot(name, &writer);
if (!res) {
return res;
@@ -1250,7 +1246,7 @@
// It doesn't really matter the order, we just want copies that reference
// blocks that won't exist if the partition shrinks.
AssertionResult ShiftAllSnapshotBlocks(const std::string& name, uint64_t old_size) {
- std::unique_ptr<ISnapshotWriter> writer;
+ std::unique_ptr<ICowWriter> writer;
if (auto res = MapUpdateSnapshot(name, &writer); !res) {
return res;
}
@@ -1273,7 +1269,13 @@
return AssertionFailure() << "Unable to finalize writer for " << name;
}
- auto hash = HashSnapshot(writer.get());
+ auto old_partition = "/dev/block/mapper/" + GetOtherPartitionName(name);
+ auto reader = writer->OpenFileDescriptor(old_partition);
+ if (!reader) {
+ return AssertionFailure() << "Could not open file descriptor for " << name;
+ }
+
+ auto hash = HashSnapshot(reader.get());
if (hash.empty()) {
return AssertionFailure() << "Unable to hash snapshot writer for " << name;
}
@@ -1428,7 +1430,7 @@
for (auto* partition : partitions) {
AddOperation(partition);
- std::unique_ptr<ISnapshotWriter> writer;
+ std::unique_ptr<ICowWriter> writer;
auto res = MapUpdateSnapshot(partition->partition_name() + "_b", &writer);
ASSERT_TRUE(res);
ASSERT_TRUE(writer->AddZeroBlocks(0, 1));
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
deleted file mode 100644
index 0ea424c..0000000
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-//
-// Copyright (C) 2020 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.
-//
-
-#include <libsnapshot/snapshot_writer.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <payload_consumer/file_descriptor.h>
-#include "libsnapshot_cow/writer_v2.h"
-#include "snapshot_reader.h"
-
-namespace android {
-namespace snapshot {
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-using chromeos_update_engine::FileDescriptor;
-
-void CompressedSnapshotWriter::SetSourceDevice(const std::string& source_device) {
- source_device_ = {source_device};
-}
-
-borrowed_fd CompressedSnapshotWriter::GetSourceFd() {
- if (!source_device_) {
- LOG(ERROR) << "Attempted to read from source device but none was set";
- return borrowed_fd{-1};
- }
-
- if (source_fd_ < 0) {
- source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
- if (source_fd_ < 0) {
- PLOG(ERROR) << "open " << *source_device_;
- return borrowed_fd{-1};
- }
- }
- return source_fd_;
-}
-
-CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options) : options_(options) {}
-
-bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
- cow_device_ = std::move(cow_device);
- return true;
-}
-
-bool CompressedSnapshotWriter::Finalize() {
- return cow_->Finalize();
-}
-
-uint64_t CompressedSnapshotWriter::GetCowSize() {
- return cow_->GetCowSize();
-}
-
-std::unique_ptr<CowReader> CompressedSnapshotWriter::OpenCowReader() const {
- unique_fd cow_fd(dup(cow_device_.get()));
- if (cow_fd < 0) {
- PLOG(ERROR) << "dup COW device";
- return nullptr;
- }
-
- auto cow = std::make_unique<CowReader>();
- if (!cow->Parse(std::move(cow_fd))) {
- LOG(ERROR) << "Unable to read COW";
- return nullptr;
- }
- return cow;
-}
-
-bool CompressedSnapshotWriter::VerifyMergeOps() const noexcept {
- auto cow_reader = OpenCowReader();
- if (cow_reader == nullptr) {
- LOG(ERROR) << "Couldn't open CowReader";
- return false;
- }
- return cow_reader->VerifyMergeOps();
-}
-
-std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
- auto cow = OpenCowReader();
- if (cow == nullptr) {
- return nullptr;
- }
-
- auto reader = std::make_unique<CompressedSnapshotReader>();
- if (!reader->SetCow(std::move(cow))) {
- LOG(ERROR) << "Unable to initialize COW reader";
- return nullptr;
- }
- if (source_device_) {
- reader->SetSourceDevice(*source_device_);
- }
-
- if (options_.max_blocks) {
- reader->SetBlockDeviceSize(*options_.max_blocks * options_.block_size);
- }
-
- return reader;
-}
-
-bool CompressedSnapshotWriter::AddCopy(uint64_t new_block, uint64_t old_block,
- uint64_t num_blocks) {
- return cow_->AddCopy(new_block, old_block, num_blocks);
-}
-
-bool CompressedSnapshotWriter::AddRawBlocks(uint64_t new_block_start, const void* data,
- size_t size) {
- return cow_->AddRawBlocks(new_block_start, data, size);
-}
-
-bool CompressedSnapshotWriter::AddXorBlocks(uint32_t new_block_start, const void* data, size_t size,
- uint32_t old_block, uint16_t offset) {
- return cow_->AddXorBlocks(new_block_start, data, size, old_block, offset);
-}
-
-bool CompressedSnapshotWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
- return cow_->AddZeroBlocks(new_block_start, num_blocks);
-}
-
-bool CompressedSnapshotWriter::AddLabel(uint64_t label) {
- return cow_->AddLabel(label);
-}
-
-bool CompressedSnapshotWriter::AddSequenceData(size_t num_ops, const uint32_t* data) {
- return cow_->AddSequenceData(num_ops, data);
-}
-
-bool CompressedSnapshotWriter::Initialize() {
- unique_fd cow_fd(dup(cow_device_.get()));
- if (cow_fd < 0) {
- PLOG(ERROR) << "dup COW device";
- return false;
- }
-
- auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
- if (!cow->Initialize(std::nullopt)) {
- return false;
- }
- cow_ = std::move(cow);
- return true;
-}
-
-bool CompressedSnapshotWriter::InitializeAppend(uint64_t label) {
- unique_fd cow_fd(dup(cow_device_.get()));
- if (cow_fd < 0) {
- PLOG(ERROR) << "dup COW device";
- return false;
- }
-
- auto cow = std::make_unique<CowWriterV2>(options_, std::move(cow_fd));
- if (!cow->Initialize(label)) {
- return false;
- }
- cow_ = std::move(cow);
- return true;
-}
-
-uint32_t CompressedSnapshotWriter::GetBlockSize() const {
- return cow_->GetBlockSize();
-}
-
-std::optional<uint32_t> CompressedSnapshotWriter::GetMaxBlocks() const {
- return cow_->GetMaxBlocks();
-}
-
-} // namespace snapshot
-} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_writer_test.cpp b/fs_mgr/libsnapshot/snapshot_writer_test.cpp
deleted file mode 100644
index a03632b..0000000
--- a/fs_mgr/libsnapshot/snapshot_writer_test.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Copyright (C) 2021 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.
-//
-
-#include <libsnapshot/snapshot.h>
-
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-#include <libsnapshot/snapshot_writer.h>
-#include <payload_consumer/file_descriptor.h>
-
-namespace android::snapshot {
-class CompressedSnapshotWriterTest : public ::testing::Test {
- public:
- static constexpr size_t BLOCK_SIZE = 4096;
-};
-
-TEST_F(CompressedSnapshotWriterTest, ReadAfterWrite) {
- TemporaryFile cow_device_file{};
- android::snapshot::CowOptions options{.block_size = BLOCK_SIZE};
- android::snapshot::CompressedSnapshotWriter snapshot_writer{options};
- ASSERT_TRUE(snapshot_writer.SetCowDevice(android::base::unique_fd{cow_device_file.fd}));
- ASSERT_TRUE(snapshot_writer.Initialize());
- std::vector<unsigned char> buffer;
- buffer.resize(BLOCK_SIZE);
- std::fill(buffer.begin(), buffer.end(), 123);
-
- ASSERT_TRUE(snapshot_writer.AddRawBlocks(0, buffer.data(), buffer.size()));
- ASSERT_TRUE(snapshot_writer.Finalize());
- auto cow_reader = snapshot_writer.OpenReader();
- ASSERT_NE(cow_reader, nullptr);
- ASSERT_TRUE(snapshot_writer.AddRawBlocks(1, buffer.data(), buffer.size()));
- ASSERT_TRUE(snapshot_writer.AddRawBlocks(2, buffer.data(), buffer.size()));
- ASSERT_TRUE(snapshot_writer.Finalize());
- // After wrigin some data, if we call OpenReader() again, writes should
- // be visible to the newly opened reader. update_engine relies on this
- // behavior for verity writes.
- cow_reader = snapshot_writer.OpenReader();
- ASSERT_NE(cow_reader, nullptr);
- std::vector<unsigned char> read_back;
- read_back.resize(buffer.size());
- cow_reader->Seek(BLOCK_SIZE, SEEK_SET);
- const auto bytes_read = cow_reader->Read(read_back.data(), read_back.size());
- ASSERT_EQ((size_t)(bytes_read), BLOCK_SIZE);
- ASSERT_EQ(read_back, buffer);
-}
-
-} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index ad3f83c..38eb719 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -133,7 +133,6 @@
// Write the "new" system partition.
auto system_target_name = "system" + target_slot;
- auto source_device = "/dev/block/mapper/" + system_source_name;
CreateLogicalPartitionParams clpp = {
.block_device = fs_mgr_get_super_partition_name(target_slot_number),
.metadata_slot = {target_slot_number},
@@ -141,15 +140,11 @@
.partition_opener = &opener,
.timeout_ms = 10s,
};
- auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
+ auto writer = sm->OpenSnapshotWriter(clpp, std::nullopt);
if (!writer) {
std::cerr << "Could not open snapshot writer.\n";
return false;
}
- if (!writer->Initialize()) {
- std::cerr << "Could not initialize snapshot for writing.\n";
- return false;
- }
for (uint64_t block = 0; block < system_source_size / 4096; block++) {
if (!writer->AddCopy(block, block)) {
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index a224f6b..2eac347 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -130,12 +130,7 @@
return true;
}
-std::string HashSnapshot(ISnapshotWriter* writer) {
- auto reader = writer->OpenReader();
- if (!reader) {
- return {};
- }
-
+std::string HashSnapshot(ICowWriter::FileDescriptor* reader) {
SHA256_CTX ctx;
SHA256_Init(&ctx);
diff --git a/init/Android.bp b/init/Android.bp
index 41c7a95..f62d7b7 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -265,8 +265,8 @@
],
}
-cc_binary {
- name: "init_second_stage",
+cc_defaults {
+ name: "init_second_stage_defaults",
recovery_available: true,
stem: "init",
defaults: ["init_defaults"],
@@ -304,9 +304,22 @@
],
},
},
+}
+
+cc_binary {
+ name: "init_second_stage",
+ defaults: ["init_second_stage_defaults"],
+}
+
+cc_binary {
+ name: "init_second_stage.microdroid",
+ defaults: ["init_second_stage_defaults"],
+ cflags: ["-DMICRODROID"],
+ installable: false,
visibility: ["//packages/modules/Virtualization/microdroid"],
}
+
soong_config_module_type {
name: "init_first_stage_cc_defaults",
module_type: "cc_defaults",
@@ -324,12 +337,8 @@
installable: false,
},
},
-}
-cc_binary {
- name: "init_first_stage",
stem: "init",
- defaults: ["init_first_stage_defaults"],
srcs: [
"block_dev_initializer.cpp",
@@ -443,6 +452,18 @@
install_in_root: true,
}
+cc_binary {
+ name: "init_first_stage",
+ defaults: ["init_first_stage_defaults"],
+}
+
+cc_binary {
+ name: "init_first_stage.microdroid",
+ defaults: ["init_first_stage_defaults"],
+ cflags: ["-DMICRODROID"],
+ installable: false,
+}
+
phony {
name: "init_system",
required: ["init_second_stage"],