Merge "libsnapshot: Move snapshot metadata to super partition." into main

This commit is contained in:
Treehugger Robot 2024-08-28 17:39:29 +00:00 committed by Gerrit Code Review
commit 40f2bfd604
16 changed files with 618 additions and 23 deletions

View file

@ -186,6 +186,7 @@ cc_binary {
"libprotobuf-cpp-lite",
"libsparse",
"libutils",
"libselinux",
],
static_libs: [

View file

@ -80,10 +80,8 @@
using namespace std::chrono_literals;
bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
bool fs_mgr_is_device_unlocked();
bool fs_mgr_is_ext4(const std::string& blk_device);
bool fs_mgr_is_f2fs(const std::string& blk_device);
bool fs_mgr_filesystem_available(const std::string& filesystem);

View file

@ -104,6 +104,12 @@ int fs_mgr_setup_verity(android::fs_mgr::FstabEntry* fstab, bool wait_for_verity
// returned. Otherwise, it will use the current slot.
std::string fs_mgr_get_super_partition_name(int slot = -1);
// Set readonly for the block device
bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
// Check if the block device has ext4 filesystem
bool fs_mgr_is_ext4(const std::string& blk_device);
enum FsMgrUmountStatus : int {
SUCCESS = 0,
ERROR_UNKNOWN = 1 << 0,

View file

@ -46,6 +46,7 @@ cc_defaults {
"libfstab",
"libsnapuserd_client",
"libz",
"libselinux",
],
header_libs: [
"libfiemap_headers",
@ -91,6 +92,7 @@ filegroup {
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
"scratch_super.cpp",
],
}
@ -351,6 +353,7 @@ cc_binary {
],
srcs: [
"snapshotctl.cpp",
"scratch_super.cpp",
],
static_libs: [
"libbrotli",

View file

@ -13,6 +13,7 @@
// limitations under the License.
#include "device_info.h"
#include "scratch_super.h"
#include <android-base/logging.h>
#include <fs_mgr.h>
@ -37,8 +38,24 @@ constexpr bool kIsRecovery = true;
constexpr bool kIsRecovery = false;
#endif
DeviceInfo::DeviceInfo() {
std::string scratch_device = android::snapshot::GetScratchOtaMetadataPartition();
if (!scratch_device.empty()) {
std::string scratch_metadata =
android::snapshot::MapScratchOtaMetadataPartition(scratch_device);
if (!scratch_metadata.empty()) {
SetMetadataDir(scratch_metadata);
SetTempMetadata();
}
}
}
std::string DeviceInfo::GetMetadataDir() const {
return "/metadata/ota"s;
return metadata_dir_;
}
void DeviceInfo::SetMetadataDir(const std::string& value) {
metadata_dir_ = value;
}
std::string DeviceInfo::GetSlotSuffix() const {

View file

@ -29,6 +29,7 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
using MergeStatus = ::aidl::android::hardware::boot::MergeStatus;
public:
DeviceInfo();
std::string GetMetadataDir() const override;
std::string GetSlotSuffix() const override;
std::string GetOtherSlotSuffix() const override;
@ -42,14 +43,19 @@ class DeviceInfo final : public SnapshotManager::IDeviceInfo {
std::unique_ptr<IImageManager> OpenImageManager() const override;
bool IsFirstStageInit() const override;
android::dm::IDeviceMapper& GetDeviceMapper() override;
void SetMetadataDir(const std::string& value);
void set_first_stage_init(bool value) { first_stage_init_ = value; }
bool IsTempMetadata() const override { return temp_metadata_; }
void SetTempMetadata() { temp_metadata_ = true; }
private:
bool EnsureBootHal();
android::fs_mgr::PartitionOpener opener_;
bool first_stage_init_ = false;
// Default value
std::string metadata_dir_ = "/metadata/ota";
bool temp_metadata_ = false;
#ifdef LIBSNAPSHOT_USE_HAL
std::unique_ptr<::android::hal::BootControlClient> boot_control_;
#endif

View file

@ -111,6 +111,7 @@ class ISnapshotManager {
virtual bool IsFirstStageInit() const = 0;
virtual std::unique_ptr<IImageManager> OpenImageManager() const = 0;
virtual android::dm::IDeviceMapper& GetDeviceMapper() = 0;
virtual bool IsTempMetadata() const = 0;
// Helper method for implementing OpenImageManager.
std::unique_ptr<IImageManager> OpenImageManager(const std::string& gsid_dir) const;
@ -329,6 +330,10 @@ class SnapshotManager final : public ISnapshotManager {
// might be needed to perform first-stage mounts.
static bool IsSnapshotManagerNeeded();
// Map the temp OTA metadata partition from super
static bool MapTempOtaMetadataPartitionIfNeeded(
const std::function<bool(const std::string&)>& init);
// Helper function for second stage init to restorecon on the rollback indicator.
static std::string GetGlobalRollbackIndicatorPath();

View file

@ -79,7 +79,7 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
: TestDeviceInfo(fake_super) {
set_slot_suffix(slot_suffix);
}
std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
std::string GetMetadataDir() const override { return metadata_dir_; }
std::string GetSlotSuffix() const override { return slot_suffix_; }
std::string GetOtherSlotSuffix() const override { return slot_suffix_ == "_a" ? "_b" : "_a"; }
std::string GetSuperDevice([[maybe_unused]] uint32_t slot) const override { return "super"; }
@ -120,6 +120,7 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
void set_dm(android::dm::IDeviceMapper* dm) { dm_ = dm; }
MergeStatus merge_status() const { return merge_status_; }
bool IsTempMetadata() const override { return temp_metadata_; }
private:
std::string slot_suffix_ = "_a";
@ -129,6 +130,8 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
bool first_stage_init_ = false;
std::unordered_set<uint32_t> unbootable_slots_;
android::dm::IDeviceMapper* dm_ = nullptr;
std::string metadata_dir_ = "/metadata/ota/test";
bool temp_metadata_ = false;
};
class DeviceMapperWrapper : public android::dm::IDeviceMapper {

View file

@ -0,0 +1,417 @@
// Copyright (C) 2024 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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <selinux/selinux.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
#include <libsnapshot/snapshot.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
#include <fstab/fstab.h>
#include <liblp/builder.h>
#include <storage_literals/storage_literals.h>
#include <algorithm>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "device_info.h"
#include "scratch_super.h"
using namespace std::literals;
using namespace android::dm;
using namespace android::fs_mgr;
using namespace android::storage_literals;
namespace android {
namespace snapshot {
static bool UmountScratch() {
auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
std::error_code ec;
if (std::filesystem::remove_all(ota_dir, ec) == static_cast<std::uintmax_t>(-1)) {
LOG(ERROR) << "Failed to remove OTA directory: " << ec.message();
return false;
}
if (umount(kOtaMetadataMount) != 0) {
PLOG(ERROR) << "UmountScratch failed";
return false;
}
LOG(INFO) << "umount scratch_super success";
return true;
}
bool CleanupScratchOtaMetadataIfPresent(const ISnapshotManager::IDeviceInfo* info) {
if (!UmountScratch()) {
return false;
}
std::unique_ptr<MetadataBuilder> builder;
const auto partition_name = android::base::Basename(kOtaMetadataMount);
const std::vector<int> slots = {0, 1};
if (info == nullptr) {
info = new android::snapshot::DeviceInfo();
}
std::string super_device;
if (info->IsTestDevice()) {
super_device = "super";
} else {
super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
}
const auto& opener = info->GetPartitionOpener();
std::string slot_suffix = info->GetSlotSuffix();
int slot = SlotNumberForSlotSuffix(slot_suffix);
// Walk both the slots and clean up metadata related to scratch space from
// both the slots.
for (auto slot : slots) {
std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(opener, super_device, slot);
if (!builder) {
return false;
}
if (builder->FindPartition(partition_name) != nullptr) {
builder->RemovePartition(partition_name);
auto metadata = builder->Export();
if (!metadata) {
return false;
}
if (!UpdatePartitionTable(info->GetPartitionOpener(), super_device, *metadata.get(),
slot)) {
LOG(ERROR) << "UpdatePartitionTable failed for slot: " << slot;
return false;
}
if (DestroyLogicalPartition(partition_name)) {
LOG(INFO) << "CleanupScratchOtaMetadata success for slot: " << slot;
}
}
}
return true;
}
static bool SetupOTADirs() {
if (setfscreatecon(android::snapshot::kOtaMetadataFileContext)) {
PLOG(ERROR) << "setfscreatecon failed: " << android::snapshot::kOtaMetadataFileContext;
return false;
}
const auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
if (mkdir(ota_dir.c_str(), 0755) != 0 && errno != EEXIST) {
PLOG(ERROR) << "mkdir " << ota_dir;
return false;
}
const auto snapshot_dir = ota_dir + "/" + "snapshots";
if (mkdir(snapshot_dir.c_str(), 0755) != 0 && errno != EEXIST) {
PLOG(ERROR) << "mkdir " << snapshot_dir;
return false;
}
if (setfscreatecon(nullptr)) {
PLOG(ERROR) << "setfscreatecon null";
return false;
}
return true;
}
static bool MountScratch(const std::string& device_path) {
if (access(device_path.c_str(), R_OK | W_OK)) {
LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
return false;
}
std::string filesystem_candidate;
if (fs_mgr_is_ext4(device_path)) {
filesystem_candidate = "ext4";
} else {
LOG(ERROR) << "Scratch partition is not ext4";
return false;
}
if (setfscreatecon(android::snapshot::kOtaMetadataFileContext)) {
PLOG(ERROR) << "setfscreatecon failed: " << android::snapshot::kOtaMetadataFileContext;
return false;
}
if (mkdir(kOtaMetadataMount, 0755) && (errno != EEXIST)) {
PLOG(ERROR) << "create " << kOtaMetadataMount;
return false;
}
android::fs_mgr::FstabEntry entry;
entry.blk_device = device_path;
entry.mount_point = kOtaMetadataMount;
entry.flags = MS_NOATIME;
entry.flags |= MS_SYNCHRONOUS;
entry.fs_options = "nodiscard";
fs_mgr_set_blk_ro(device_path, false);
entry.fs_mgr_flags.check = true;
bool mounted = false;
entry.fs_type = filesystem_candidate.c_str();
if (fs_mgr_do_mount_one(entry) == 0) {
mounted = true;
}
if (setfscreatecon(nullptr)) {
PLOG(ERROR) << "setfscreatecon null";
return false;
}
if (!mounted) {
rmdir(kOtaMetadataMount);
return false;
}
return true;
}
static bool MakeScratchFilesystem(const std::string& scratch_device) {
std::string fs_type;
std::string command;
if (!access(kMkExt4, X_OK)) {
fs_type = "ext4";
command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M "s + kOtaMetadataMount;
} else {
LOG(ERROR) << "No supported mkfs command or filesystem driver available, supported "
"filesystems "
"are: f2fs, ext4";
return false;
}
command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null";
fs_mgr_set_blk_ro(scratch_device, false);
auto ret = system(command.c_str());
if (ret) {
LOG(ERROR) << "make " << fs_type << " filesystem on " << scratch_device
<< " return=" << ret;
return false;
}
return true;
}
static bool CreateDynamicScratch(const ISnapshotManager::IDeviceInfo* info,
std::string* scratch_device) {
const auto partition_name = android::base::Basename(kOtaMetadataMount);
auto& dm = DeviceMapper::Instance();
if (info == nullptr) {
info = new android::snapshot::DeviceInfo();
}
std::string super_device;
if (info->IsTestDevice()) {
super_device = "super";
} else {
super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
}
bool partition_exists = dm.GetState(partition_name) != DmDeviceState::INVALID;
if (partition_exists) {
LOG(ERROR) << "Partition already exists: " << partition_name;
return false;
}
const auto& opener = info->GetPartitionOpener();
std::string slot_suffix = info->GetSlotSuffix();
int slot = SlotNumberForSlotSuffix(slot_suffix);
std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(opener, super_device, slot);
if (!builder) {
LOG(ERROR) << "open " << super_device << " failed";
return false;
}
auto partition = builder->FindPartition(partition_name);
partition_exists = partition != nullptr;
if (partition_exists) {
LOG(ERROR) << "Partition exists in super metadata";
return false;
}
partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
if (!partition) {
LOG(ERROR) << "AddPartition failed " << partition_name;
return false;
}
auto free_space = builder->AllocatableSpace() - builder->UsedSpace();
if (free_space < kOtaMetadataPartitionSize) {
LOG(ERROR) << "No space in super partition. Free space: " << free_space
<< " Requested space: " << kOtaMetadataPartitionSize;
return false;
}
LOG(INFO) << "CreateDynamicScratch: free_space: " << free_space
<< " scratch_size: " << kOtaMetadataPartitionSize << " slot_number: " << slot;
if (!builder->ResizePartition(partition, kOtaMetadataPartitionSize)) {
LOG(ERROR) << "ResizePartition failed: " << partition_name << " free_space: " << free_space
<< " scratch_size: " << kOtaMetadataPartitionSize;
return false;
}
auto metadata = builder->Export();
CreateLogicalPartitionParams params;
if (!metadata ||
!UpdatePartitionTable(info->GetPartitionOpener(), super_device, *metadata.get(), slot)) {
LOG(ERROR) << "UpdatePartitionTable failed: " << partition_name;
return false;
}
params = {
.block_device = super_device,
.metadata_slot = slot,
.partition_name = partition_name,
.force_writable = true,
.timeout_ms = 10s,
.partition_opener = &info->GetPartitionOpener(),
};
if (!CreateLogicalPartition(params, scratch_device)) {
LOG(ERROR) << "CreateLogicalPartition failed";
return false;
}
LOG(INFO) << "Scratch device created successfully: " << *scratch_device << " slot: " << slot;
return true;
}
bool IsScratchOtaMetadataOnSuper() {
auto partition_name = android::base::Basename(kOtaMetadataMount);
auto source_slot = fs_mgr_get_slot_suffix();
auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
const auto super_device =
kPhysicalDevice + fs_mgr_get_super_partition_name(!source_slot_number);
auto metadata = android::fs_mgr::ReadMetadata(super_device, !source_slot_number);
if (!metadata) {
return false;
}
auto partition = android::fs_mgr::FindPartition(*metadata.get(), partition_name);
if (!partition) {
return false;
}
auto& dm = DeviceMapper::Instance();
if (dm.GetState(partition_name) == DmDeviceState::ACTIVE) {
LOG(INFO) << "Partition: " << partition_name << " is active";
return true;
}
CreateLogicalPartitionParams params = {
.block_device = super_device,
.metadata = metadata.get(),
.partition = partition,
};
std::string scratch_path;
if (!CreateLogicalPartition(params, &scratch_path)) {
LOG(ERROR) << "Could not create logical partition: " << partition_name;
return false;
}
LOG(INFO) << "Scratch device: " << scratch_path << " created successfully";
return true;
}
std::string GetScratchOtaMetadataPartition() {
std::string device;
auto& dm = DeviceMapper::Instance();
auto partition_name = android::base::Basename(kOtaMetadataMount);
bool invalid_partition = (dm.GetState(partition_name) == DmDeviceState::INVALID);
if (!invalid_partition && dm.GetDmDevicePathByName(partition_name, &device)) {
return device;
}
return "";
}
static bool ScratchAlreadyMounted(const std::string& mount_point) {
android::fs_mgr::Fstab fstab;
if (!ReadFstabFromProcMounts(&fstab)) {
return false;
}
for (const auto& entry : GetEntriesForMountPoint(&fstab, mount_point)) {
if (entry->fs_type == "ext4") {
return true;
}
}
return false;
}
std::string MapScratchOtaMetadataPartition(const std::string& scratch_device) {
if (!ScratchAlreadyMounted(kOtaMetadataMount)) {
if (!MountScratch(scratch_device)) {
return "";
}
}
auto ota_dir = std::string(kOtaMetadataMount) + "/" + "ota";
if (access(ota_dir.c_str(), F_OK) != 0) {
return "";
}
return ota_dir;
}
// Entry point to create a scratch device on super partition
// This will create a 1MB space in super. The space will be
// from the current active slot. Ext4 filesystem will be created
// on this scratch device and all the OTA related directories
// will be created.
bool CreateScratchOtaMetadataOnSuper(const ISnapshotManager::IDeviceInfo* info) {
std::string scratch_device;
if (!CreateDynamicScratch(info, &scratch_device)) {
LOG(ERROR) << "CreateDynamicScratch failed";
return false;
}
if (!MakeScratchFilesystem(scratch_device)) {
LOG(ERROR) << "MakeScratchFilesystem failed";
return false;
}
if (!MountScratch(scratch_device)) {
LOG(ERROR) << "MountScratch failed";
return false;
}
if (!SetupOTADirs()) {
LOG(ERROR) << "SetupOTADirs failed";
return false;
}
return true;
}
} // namespace snapshot
} // namespace android

View file

@ -0,0 +1,33 @@
// Copyright (C) 2024 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
namespace android {
namespace snapshot {
constexpr char kMkExt4[] = "/system/bin/mke2fs";
constexpr char kOtaMetadataFileContext[] = "u:object_r:ota_metadata_file:s0";
constexpr char kOtaMetadataMount[] = "/mnt/scratch_ota_metadata_super";
const size_t kOtaMetadataPartitionSize = uint64_t(1 * 1024 * 1024);
constexpr char kPhysicalDevice[] = "/dev/block/by-name/";
bool IsScratchOtaMetadataOnSuper();
std::string GetScratchOtaMetadataPartition();
std::string MapScratchOtaMetadataPartition(const std::string& device);
bool CreateScratchOtaMetadataOnSuper(const ISnapshotManager::IDeviceInfo* info = nullptr);
bool CleanupScratchOtaMetadataIfPresent(const ISnapshotManager::IDeviceInfo* info = nullptr);
} // namespace snapshot
} // namespace android

View file

@ -48,6 +48,7 @@
#include <libsnapshot/snapshot_stats.h>
#include "device_info.h"
#include "partition_cow_creator.h"
#include "scratch_super.h"
#include "snapshot_metadata_updater.h"
#include "utility.h"
@ -117,7 +118,11 @@ std::unique_ptr<SnapshotManager> SnapshotManager::New(IDeviceInfo* info) {
info = new DeviceInfo();
}
return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
auto sm = std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
if (info->IsTempMetadata()) {
LOG(INFO) << "Using temp metadata from super";
}
return sm;
}
std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) {
@ -1110,6 +1115,13 @@ UpdateState SnapshotManager::ProcessUpdateState(const std::function<bool()>& cal
if (result.state == UpdateState::MergeFailed) {
AcknowledgeMergeFailure(result.failure_code);
}
if (result.state == UpdateState::MergeCompleted) {
if (device_->IsTempMetadata()) {
CleanupScratchOtaMetadataIfPresent();
}
}
if (result.state != UpdateState::Merging) {
// Either there is no merge, or the merge was finished, so no need
// to keep waiting.
@ -2310,7 +2322,27 @@ bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>*
}
bool SnapshotManager::IsSnapshotManagerNeeded() {
return access(kBootIndicatorPath, F_OK) == 0;
if (access(kBootIndicatorPath, F_OK) == 0) {
return true;
}
if (IsScratchOtaMetadataOnSuper()) {
return true;
}
return false;
}
bool SnapshotManager::MapTempOtaMetadataPartitionIfNeeded(
const std::function<bool(const std::string&)>& init) {
auto device = android::snapshot::GetScratchOtaMetadataPartition();
if (!device.empty()) {
init(device);
if (android::snapshot::MapScratchOtaMetadataPartition(device).empty()) {
return false;
}
}
return true;
}
std::string SnapshotManager::GetGlobalRollbackIndicatorPath() {
@ -2397,6 +2429,12 @@ bool SnapshotManager::MapAllPartitions(LockedFile* lock, const std::string& supe
continue;
}
if (GetPartitionName(partition) ==
android::base::Basename(android::snapshot::kOtaMetadataMount)) {
LOG(INFO) << "Partition: " << GetPartitionName(partition) << " skipping";
continue;
}
CreateLogicalPartitionParams params = {
.block_device = super_device,
.metadata = metadata.get(),

View file

@ -47,6 +47,7 @@
#include <android/snapshot/snapshot.pb.h>
#include <libsnapshot/test_helpers.h>
#include "partition_cow_creator.h"
#include "scratch_super.h"
#include "utility.h"
// Mock classes are not used. Header included to ensure mocked class definition aligns with the
@ -1342,6 +1343,15 @@ class SnapshotUpdateTest : public SnapshotTest {
DynamicPartitionGroup* group_ = nullptr;
};
TEST_F(SnapshotUpdateTest, SuperOtaMetadataTest) {
auto info = new TestDeviceInfo(fake_super);
ASSERT_TRUE(CreateScratchOtaMetadataOnSuper(info));
std::string scratch_device = GetScratchOtaMetadataPartition();
ASSERT_NE(scratch_device, "");
ASSERT_NE(MapScratchOtaMetadataPartition(scratch_device), "");
ASSERT_TRUE(CleanupScratchOtaMetadataIfPresent(info));
}
// Test full update flow executed by update_engine. Some partitions uses super empty space,
// some uses images, and some uses both.
// Also test UnmapUpdateSnapshot unmaps everything.

View file

@ -16,7 +16,6 @@
#include <sysexits.h>
#include <unistd.h>
#include <chrono>
#include <filesystem>
#include <fstream>
@ -46,6 +45,7 @@
#include <storage_literals/storage_literals.h>
#include "partition_cow_creator.h"
#include "scratch_super.h"
#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
#include <BootControlClient.h>
@ -57,6 +57,8 @@ using namespace android::storage_literals;
using android::base::LogdLogger;
using android::base::StderrLogger;
using android::base::TeeLogger;
using namespace android::dm;
using namespace android::fs_mgr;
using android::fs_mgr::CreateLogicalPartitionParams;
using android::fs_mgr::FindPartition;
using android::fs_mgr::GetPartitionSize;
@ -97,7 +99,7 @@ namespace snapshot {
#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
class MapSnapshots {
public:
MapSnapshots(std::string path = "");
MapSnapshots(std::string path = "", bool metadata_super = false);
bool CreateSnapshotDevice(std::string& partition_name, std::string& patch);
bool InitiateThreadedSnapshotWrite(std::string& pname, std::string& snapshot_patch);
bool FinishSnapshotWrites();
@ -122,15 +124,12 @@ class MapSnapshots {
std::vector<std::string> patchfiles_;
chromeos_update_engine::DeltaArchiveManifest manifest_;
bool metadata_super_ = false;
};
MapSnapshots::MapSnapshots(std::string path) {
sm_ = SnapshotManager::New();
if (!sm_) {
std::cout << "Failed to create snapshotmanager";
exit(1);
}
MapSnapshots::MapSnapshots(std::string path, bool metadata_super) {
snapshot_dir_path_ = path + "/";
metadata_super_ = metadata_super;
}
std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
@ -150,6 +149,12 @@ std::string MapSnapshots::GetGroupName(const android::fs_mgr::LpMetadata& pt,
}
bool MapSnapshots::PrepareUpdate() {
if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
LOG(ERROR) << "Failed to create OTA metadata on super";
return false;
}
sm_ = SnapshotManager::New();
auto source_slot = fs_mgr_get_slot_suffix();
auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
@ -234,14 +239,22 @@ bool MapSnapshots::PrepareUpdate() {
bool MapSnapshots::GetCowDevicePath(std::string partition_name, std::string* cow_path) {
auto& dm = android::dm::DeviceMapper::Instance();
std::string cow_device = partition_name + "-cow";
std::string cow_device = partition_name + "-cow-img";
if (metadata_super_) {
// If COW device exists on /data, then data wipe cannot be done.
if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
LOG(ERROR) << "COW device exists on /data: " << *cow_path;
return false;
}
}
cow_device = partition_name + "-cow";
if (dm.GetDmDevicePathByName(cow_device, cow_path)) {
return true;
}
LOG(INFO) << "Failed to find cow path: " << cow_device << " Checking the device for -img path";
// If the COW device exists only on /data
cow_device = partition_name + "-cow-img";
if (!dm.GetDmDevicePathByName(cow_device, cow_path)) {
LOG(ERROR) << "Failed to cow path: " << cow_device;
return false;
@ -321,6 +334,12 @@ bool MapSnapshots::ApplyUpdate() {
}
bool MapSnapshots::BeginUpdate() {
if (metadata_super_ && !CreateScratchOtaMetadataOnSuper()) {
LOG(ERROR) << "Failed to create OTA metadata on super";
return false;
}
sm_ = SnapshotManager::New();
lock_ = sm_->LockExclusive();
std::vector<std::string> snapshots;
sm_->ListSnapshots(lock_.get(), &snapshots);
@ -470,10 +489,12 @@ bool MapSnapshots::FinishSnapshotWrites() {
}
bool MapSnapshots::UnmapCowImagePath(std::string& name) {
sm_ = SnapshotManager::New();
return sm_->UnmapCowImage(name);
}
bool MapSnapshots::DeleteSnapshots() {
sm_ = SnapshotManager::New();
lock_ = sm_->LockExclusive();
if (!sm_->RemoveAllUpdateState(lock_.get())) {
LOG(ERROR) << "Remove All Update State failed";
@ -583,13 +604,19 @@ bool ApplyUpdate(int argc, char** argv) {
}
if (argc < 3) {
std::cerr << " apply-update <directory location where snapshot patches are present>"
std::cerr << " apply-update <directory location where snapshot patches are present> {-w}"
" Apply the snapshots to the COW block device\n";
return false;
}
std::string path = std::string(argv[2]);
MapSnapshots cow(path);
bool metadata_on_super = false;
if (argc == 4) {
if (std::string(argv[3]) == "-w") {
metadata_on_super = true;
}
}
MapSnapshots cow(path, metadata_on_super);
if (!cow.ApplyUpdate()) {
return false;
}
@ -607,7 +634,7 @@ bool MapPrecreatedSnapshots(int argc, char** argv) {
}
if (argc < 3) {
std::cerr << " map-snapshots <directory location where snapshot patches are present>"
std::cerr << " map-snapshots <directory location where snapshot patches are present> {-w}"
" Map all snapshots based on patches present in the directory\n";
return false;
}
@ -638,7 +665,14 @@ bool MapPrecreatedSnapshots(int argc, char** argv) {
}
}
MapSnapshots cow(path);
bool metadata_on_super = false;
if (argc == 4) {
if (std::string(argv[3]) == "-w") {
metadata_on_super = true;
}
}
MapSnapshots cow(path, metadata_on_super);
if (!cow.BeginUpdate()) {
LOG(ERROR) << "BeginUpdate failed";
return false;

View file

@ -42,6 +42,7 @@ cc_library_static {
static_libs: [
"libcutils_sockets",
"libfs_mgr_file_wait",
"libdm",
],
shared_libs: [
"libbase",

View file

@ -35,6 +35,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr/file_wait.h>
#include <libdm/dm.h>
#include <snapuserd/snapuserd_client.h>
namespace android {
@ -333,7 +334,21 @@ bool SnapuserdClient::QueryUpdateVerification() {
}
std::string SnapuserdClient::GetDaemonAliveIndicatorPath() {
return "/metadata/ota/" + std::string(kDaemonAliveIndicator);
std::string metadata_dir;
std::string temp_metadata_mnt = "/mnt/scratch_ota_metadata_super";
auto& dm = ::android::dm::DeviceMapper::Instance();
auto partition_name = android::base::Basename(temp_metadata_mnt);
bool invalid_partition = (dm.GetState(partition_name) == dm::DmDeviceState::INVALID);
std::string temp_device;
if (!invalid_partition && dm.GetDmDevicePathByName(partition_name, &temp_device)) {
metadata_dir = temp_metadata_mnt + "/" + "ota/";
} else {
metadata_dir = "/metadata/ota/";
}
return metadata_dir + std::string(kDaemonAliveIndicator);
}
bool SnapuserdClient::IsTransitionedDaemonReady() {

View file

@ -371,6 +371,14 @@ bool FirstStageMountVBootV2::CreateLogicalPartitions() {
}
if (SnapshotManager::IsSnapshotManagerNeeded()) {
auto init_devices = [this](const std::string& device) -> bool {
if (android::base::StartsWith(device, "/dev/block/dm-")) {
return block_dev_init_.InitDmDevice(device);
}
return block_dev_init_.InitDevices({device});
};
SnapshotManager::MapTempOtaMetadataPartitionIfNeeded(init_devices);
auto sm = SnapshotManager::NewForFirstStageMount();
if (!sm) {
return false;