Merge "libsnapshot: Partially implement OpenSnapshotWriter." am: 15f97700c2 am: b7b2d1255d am: 8b171bc688 am: c0d48d2041

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1433573

Change-Id: I5d7babec6462f596a0570b28b3f5bcf9e5434ce1
This commit is contained in:
Treehugger Robot 2020-09-30 00:06:58 +00:00 committed by Automerger Merge Worker
commit ef11411af7
16 changed files with 385 additions and 82 deletions

View file

@ -147,6 +147,7 @@ cc_binary {
static_libs: [
"libgtest_prod",
"libhealthhalutils",
"libsnapshot_cow",
"libsnapshot_nobinder",
"update_metadata-protos",
],

View file

@ -77,6 +77,7 @@ filegroup {
"snapshot_stats.cpp",
"snapshot_stub.cpp",
"snapshot_metadata_updater.cpp",
"snapshot_writer.cpp",
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
@ -215,6 +216,7 @@ cc_defaults {
"libgmock",
"liblp",
"libsnapshot",
"libsnapshot_cow",
"libsnapshot_test_helpers",
"libsparse",
],
@ -249,6 +251,7 @@ cc_binary {
static_libs: [
"libfstab",
"libsnapshot",
"libsnapshot_cow",
"update_metadata-protos",
],
shared_libs: [
@ -312,6 +315,7 @@ cc_defaults {
"libgmock", // from libsnapshot_test_helpers
"liblog",
"liblp",
"libsnapshot_cow",
"libsnapshot_test_helpers",
"libprotobuf-mutator",
],

View file

@ -32,6 +32,9 @@ namespace snapshot {
static_assert(sizeof(off_t) == sizeof(uint64_t));
using android::base::borrowed_fd;
using android::base::unique_fd;
bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
if (!ValidateNewBlock(new_block)) {
return false;
@ -98,12 +101,12 @@ bool CowWriter::ParseOptions() {
return true;
}
bool CowWriter::Initialize(android::base::unique_fd&& fd, OpenMode mode) {
bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
owned_fd_ = std::move(fd);
return Initialize(android::base::borrowed_fd{owned_fd_}, mode);
return Initialize(borrowed_fd{owned_fd_}, mode);
}
bool CowWriter::Initialize(android::base::borrowed_fd fd, OpenMode mode) {
bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
fd_ = fd;
if (!ParseOptions()) {

View file

@ -58,6 +58,9 @@ class ICowWriter {
// Return number of bytes the cow image occupies on disk.
virtual uint64_t GetCowSize() = 0;
// Returns true if AddCopy() operations are supported.
virtual bool SupportsCopyOperation() const { return true; }
const CowOptions& options() { return options_; }
protected:

View file

@ -38,9 +38,7 @@ class MockSnapshotManager : public ISnapshotManager {
(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path),
(override));
MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
(const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenSnapshotReader,
MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
(const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));

View file

@ -35,8 +35,8 @@
#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>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@ -44,10 +44,6 @@
#define DEFINED_FRIEND_TEST
#endif
namespace chromeos_update_engine {
class FileDescriptor;
} // namespace chromeos_update_engine
namespace android {
namespace fiemap {
@ -110,8 +106,6 @@ 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;
@ -187,19 +181,14 @@ class ISnapshotManager {
virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) = 0;
// Create an ICowWriter to build a snapshot against a target partition. The partition name must
// be suffixed.
virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
// Open a snapshot for reading. A file-like interface is provided through the FileDescriptor.
// In this mode, writes are not supported. The partition name must be suffixed.
virtual std::unique_ptr<FileDescriptor> OpenSnapshotReader(
// Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
// must be suffixed.
virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) = 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.
// OpenSnapshotWriter. 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
@ -310,9 +299,7 @@ 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 android::fs_mgr::CreateLogicalPartitionParams& params) override;
std::unique_ptr<FileDescriptor> OpenSnapshotReader(
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
@ -532,9 +519,39 @@ class SnapshotManager final : public ISnapshotManager {
std::string GetSnapshotDeviceName(const std::string& snapshot_name,
const SnapshotStatus& status);
// Reason for calling MapPartitionWithSnapshot.
enum class SnapshotContext {
// For writing or verification (during update_engine).
Update,
// For mounting a full readable device.
Mount,
};
struct SnapshotPaths {
// Target/base device (eg system_b), always present.
std::string target_device;
// COW path (eg system_cow). Not present if no COW is needed.
std::string cow_device;
// dm-snapshot instance. Not present in Update mode for VABC.
std::string snapshot_device;
};
// Helpers for OpenSnapshotWriter.
std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
const std::string& partition_name,
const SnapshotStatus& status,
const SnapshotPaths& paths);
std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(LockedFile* lock,
const std::string& partition_name,
const SnapshotStatus& status,
const SnapshotPaths& paths);
// Map the base device, COW devices, and snapshot device.
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
std::string* path);
SnapshotContext context, SnapshotPaths* paths);
// Map the COW devices, including the partition in super and the images.
// |params|:

View file

@ -36,9 +36,7 @@ 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 android::fs_mgr::CreateLogicalPartitionParams& params) override;
std::unique_ptr<FileDescriptor> OpenSnapshotReader(
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;

View file

@ -0,0 +1,68 @@
// 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 <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;
explicit ISnapshotWriter(const 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).
void SetSourceDevice(android::base::unique_fd&& source_fd);
virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
protected:
android::base::unique_fd source_fd_;
};
// Write directly to a dm-snapshot device.
class OnlineKernelSnapshotWriter : public ISnapshotWriter {
public:
OnlineKernelSnapshotWriter(const CowOptions& options);
// Set the device used for all writes.
void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);
bool Flush() override;
uint64_t GetCowSize() override { return cow_size_; }
virtual std::unique_ptr<FileDescriptor> OpenReader() override;
protected:
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
private:
android::base::unique_fd snapshot_fd_;
uint64_t cow_size_ = 0;
};
} // namespace snapshot
} // namespace android

View file

@ -144,6 +144,7 @@ void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::stri
// 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);
bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);
std::optional<std::string> GetHash(const std::string& path);

View file

@ -15,6 +15,7 @@
#include <libsnapshot/snapshot.h>
#include <dirent.h>
#include <fcntl.h>
#include <math.h>
#include <sys/file.h>
#include <sys/types.h>
@ -1570,7 +1571,8 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(
.timeout_ms = timeout_ms,
};
std::string ignore_path;
if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) {
if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
nullptr)) {
return false;
}
}
@ -1598,11 +1600,10 @@ static std::chrono::milliseconds GetRemainingTime(
bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
CreateLogicalPartitionParams params,
std::string* path) {
SnapshotContext context, SnapshotPaths* paths) {
auto begin = std::chrono::steady_clock::now();
CHECK(lock);
path->clear();
if (params.GetPartitionName() != params.GetDeviceName()) {
LOG(ERROR) << "Mapping snapshot with a different name is unsupported: partition_name = "
@ -1683,8 +1684,11 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
}
created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
if (paths) {
paths->target_device = base_path;
}
if (!live_snapshot_status.has_value()) {
*path = base_path;
created_devices.Release();
return true;
}
@ -1711,21 +1715,33 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
return false;
}
if (paths) {
paths->cow_device = cow_device;
}
remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
if (context == SnapshotContext::Update && IsCompressionEnabled()) {
// Stop here, we can't run dm-user yet, the COW isn't built.
return true;
}
std::string path;
if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
path)) {
&path)) {
LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
return false;
}
// No need to add params.GetPartitionName() to created_devices since it is immediately released.
if (paths) {
paths->snapshot_device = path;
}
created_devices.Release();
LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
return true;
}
@ -2438,23 +2454,86 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para
<< params.GetPartitionName();
return false;
}
return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
SnapshotPaths paths;
if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
return false;
}
if (paths.snapshot_device.empty()) {
*snapshot_path = paths.snapshot_device;
} else {
*snapshot_path = paths.target_device;
}
return true;
}
std::unique_ptr<ICowWriter> SnapshotManager::OpenSnapshotWriter(
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) {
(void)params;
// First unmap any existing mapping.
auto lock = LockShared();
if (!lock) return nullptr;
if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
LOG(ERROR) << "Cannot unmap existing snapshot before re-mapping it: "
<< params.GetPartitionName();
return nullptr;
}
LOG(ERROR) << "OpenSnapshotWriter not yet implemented";
SnapshotPaths paths;
if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
return nullptr;
}
SnapshotStatus status;
if (!paths.cow_device.empty()) {
if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
return nullptr;
}
} else {
// Currently, partition_cow_creator always creates snapshots. The
// reason is that if partition X shrinks while partition Y grows, we
// cannot bindly write to the newly freed extents in X. This would
// make the old slot unusable. So, the entire size of the target
// partition is currently considered snapshottable.
LOG(ERROR) << "No snapshot available for partition " << params.GetPartitionName();
return nullptr;
}
if (IsCompressionEnabled()) {
return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
} else {
return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
}
}
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
return nullptr;
}
std::unique_ptr<FileDescriptor> SnapshotManager::OpenSnapshotReader(
const android::fs_mgr::CreateLogicalPartitionParams& params) {
(void)params;
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
const SnapshotStatus& status, const SnapshotPaths& paths) {
CHECK(lock);
LOG(ERROR) << "OpenSnapshotReader not yet implemented";
return nullptr;
CowOptions cow_options;
cow_options.max_blocks = {status.device_size() / cow_options.block_size};
auto writer = std::make_unique<OnlineKernelSnapshotWriter>(cow_options);
std::string_view path =
paths.snapshot_device.empty() ? paths.target_device : paths.snapshot_device;
unique_fd fd(open(path.data(), O_RDWR | O_CLOEXEC));
if (fd < 0) {
PLOG(ERROR) << "open failed: " << path;
return nullptr;
}
uint64_t cow_size = status.cow_partition_size() + status.cow_file_size();
writer->SetSnapshotDevice(std::move(fd), cow_size);
return writer;
}
bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {

View file

@ -130,13 +130,7 @@ ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
return &snapshot_merge_stats;
}
std::unique_ptr<ICowWriter> SnapshotManagerStub::OpenSnapshotWriter(
const CreateLogicalPartitionParams&) {
LOG(ERROR) << __FUNCTION__ << " should never be called.";
return nullptr;
}
std::unique_ptr<FileDescriptor> SnapshotManagerStub::OpenSnapshotReader(
std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
const CreateLogicalPartitionParams&) {
LOG(ERROR) << __FUNCTION__ << " should never be called.";
return nullptr;

View file

@ -80,6 +80,7 @@ TestDeviceInfo* test_device = nullptr;
std::string fake_super;
void MountMetadata();
bool IsCompressionEnabled();
class SnapshotTest : public ::testing::Test {
public:
@ -892,42 +893,39 @@ class SnapshotUpdateTest : public SnapshotTest {
return AssertionSuccess();
}
AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path = nullptr) {
std::string real_path;
if (!sm->MapUpdateSnapshot(
CreateLogicalPartitionParams{
.block_device = fake_super,
.metadata_slot = 1,
.partition_name = name,
.timeout_ms = 10s,
.partition_opener = opener_.get(),
},
&real_path)) {
return AssertionFailure() << "Unable to map snapshot " << name;
AssertionResult MapUpdateSnapshot(const std::string& name,
std::unique_ptr<ICowWriter>* writer = nullptr) {
CreateLogicalPartitionParams params{
.block_device = fake_super,
.metadata_slot = 1,
.partition_name = name,
.timeout_ms = 10s,
.partition_opener = opener_.get(),
};
auto result = sm->OpenSnapshotWriter(params);
if (!result) {
return AssertionFailure() << "Cannot open snapshot for writing: " << name;
}
if (path) {
*path = real_path;
if (writer) {
*writer = std::move(result);
}
return AssertionSuccess() << "Mapped snapshot " << name << " to " << real_path;
return AssertionSuccess();
}
AssertionResult WriteSnapshotAndHash(const std::string& name,
std::optional<size_t> size = std::nullopt) {
std::string path;
auto res = MapUpdateSnapshot(name, &path);
AssertionResult WriteSnapshotAndHash(const std::string& name) {
std::unique_ptr<ICowWriter> writer;
auto res = MapUpdateSnapshot(name, &writer);
if (!res) {
return res;
}
std::string size_string = size ? (std::to_string(*size) + " bytes") : "";
if (!WriteRandomData(path, size, &hashes_[name])) {
return AssertionFailure() << "Unable to write " << size_string << " to " << path
<< " for partition " << name;
if (!WriteRandomData(writer.get(), &hashes_[name])) {
return AssertionFailure() << "Unable to write random data to snapshot " << name;
}
return AssertionSuccess() << "Written " << size_string << " to " << path
<< " for snapshot partition " << name
return AssertionSuccess() << "Written random data to snapshot " << name
<< ", hash: " << hashes_[name];
}
@ -1003,7 +1001,7 @@ TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
// Write some data to target partitions.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
ASSERT_TRUE(WriteSnapshotAndHash(name, partition_size));
ASSERT_TRUE(WriteSnapshotAndHash(name));
}
// Assert that source partitions aren't affected.
@ -1406,6 +1404,10 @@ void MountMetadata() {
MetadataMountedTest().TearDown();
}
bool IsCompressionEnabled() {
return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
}
TEST_F(MetadataMountedTest, Android) {
auto device = sm->EnsureMetadataMounted();
EXPECT_NE(nullptr, device);
@ -1623,7 +1625,7 @@ TEST_F(SnapshotUpdateTest, Hashtree) {
// Map and write some data to target partition.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
// Finish update.
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
@ -1655,7 +1657,7 @@ TEST_F(SnapshotUpdateTest, Overflow) {
// Map and write some data to target partitions.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
ASSERT_TRUE(WriteSnapshotAndHash("sys_b", actual_write_size));
ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
std::vector<android::dm::DeviceMapper::TargetInfo> table;
ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));

View file

@ -0,0 +1,91 @@
//
// 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>
namespace android {
namespace snapshot {
using chromeos_update_engine::FileDescriptor;
ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
source_fd_ = std::move(source_fd);
}
OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
: ISnapshotWriter(options) {}
void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
uint64_t cow_size) {
snapshot_fd_ = std::move(snapshot_fd);
cow_size_ = cow_size;
}
bool OnlineKernelSnapshotWriter::Flush() {
if (fsync(snapshot_fd_.get()) < 0) {
PLOG(ERROR) << "fsync";
return false;
}
return true;
}
bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
size_t size) {
uint64_t offset = new_block_start * options_.block_size;
if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
return false;
}
if (!android::base::WriteFully(snapshot_fd_, data, size)) {
PLOG(ERROR) << "EmitRawBlocks write";
return false;
}
return true;
}
bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
std::string zeroes(options_.block_size, 0);
for (uint64_t i = 0; i < num_blocks; i++) {
if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
return false;
}
}
return true;
}
bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
std::string buffer(options_.block_size, 0);
uint64_t offset = old_block * options_.block_size;
if (!android::base::ReadFullyAtOffset(source_fd_, buffer.data(), buffer.size(), offset)) {
PLOG(ERROR) << "EmitCopy read";
return false;
}
return EmitRawBlocks(new_block, buffer.data(), buffer.size());
}
std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
LOG(ERROR) << "OnlineKernelSnapshotWriter::OpenReader not yet implemented";
return nullptr;
}
} // namespace snapshot
} // namespace android

View file

@ -127,6 +127,48 @@ bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size,
return true;
}
bool WriteRandomData(ICowWriter* writer, std::string* hash) {
unique_fd rand(open("/dev/urandom", O_RDONLY));
if (rand < 0) {
PLOG(ERROR) << "open /dev/urandom";
return false;
}
SHA256_CTX ctx;
if (hash) {
SHA256_Init(&ctx);
}
if (!writer->options().max_blocks) {
LOG(ERROR) << "CowWriter must specify maximum number of blocks";
return false;
}
uint64_t num_blocks = writer->options().max_blocks.value();
size_t block_size = writer->options().block_size;
std::string block(block_size, '\0');
for (uint64_t i = 0; i < num_blocks; i++) {
if (!ReadFully(rand, block.data(), block.size())) {
PLOG(ERROR) << "read /dev/urandom";
return false;
}
if (!writer->AddRawBlocks(i, block.data(), block.size())) {
LOG(ERROR) << "Failed to add raw block " << i;
return false;
}
if (hash) {
SHA256_Update(&ctx, block.data(), block.size());
}
}
if (hash) {
uint8_t out[32];
SHA256_Final(out, &ctx);
*hash = ToHexString(out, sizeof(out));
}
return true;
}
std::optional<std::string> GetHash(const std::string& path) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true)) {

View file

@ -129,6 +129,7 @@ cc_defaults {
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
"libpropertyinfoparser",
"libsnapshot_cow",
"libsnapshot_init",
"libxml2",
"lib_apex_manifest_proto_lite",

View file

@ -112,6 +112,7 @@ LOCAL_STATIC_LIBRARIES := \
libmodprobe \
libext2_uuid \
libprotobuf-cpp-lite \
libsnapshot_cow \
libsnapshot_init \
update_metadata-protos \