Loading fs_mgr/libsnapshot/Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -324,6 +324,22 @@ cc_binary { "libstatslog", "libutils", ], header_libs: [ "libstorage_literals_headers", ], product_variables: { debuggable: { cppflags: [ "-DSNAPSHOTCTL_USERDEBUG_OR_ENG", ], shared_libs: [ "android.hardware.boot@1.0", "android.hardware.boot@1.1", "android.hardware.boot-V1-ndk", "libboot_control_client", ], }, }, } cc_test { Loading fs_mgr/libsnapshot/snapshotctl.cpp +143 −0 Original line number Diff line number Diff line Loading @@ -25,9 +25,27 @@ #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <fs_mgr.h> #include <fs_mgr_dm_linear.h> #include <fstab/fstab.h> #include <liblp/builder.h> #include <libsnapshot/cow_format.h> #include <libsnapshot/snapshot.h> #include <storage_literals/storage_literals.h> #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG #include <BootControlClient.h> #endif using namespace std::chrono_literals; using namespace std::string_literals; using namespace android::storage_literals; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::FindPartition; using android::fs_mgr::GetPartitionSize; using android::fs_mgr::PartitionOpener; using android::fs_mgr::ReadMetadata; using android::fs_mgr::SlotNumberForSlotSuffix; int Usage() { std::cerr << "snapshotctl: Control snapshots.\n" Loading Loading @@ -67,11 +85,136 @@ bool MergeCmdHandler(int /*argc*/, char** argv) { return false; } #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG bool CreateTestUpdate(SnapshotManager* sm) { chromeos_update_engine::DeltaArchiveManifest manifest; // We only copy system, to simplify things. manifest.set_partial_update(true); auto dap = manifest.mutable_dynamic_partition_metadata(); dap->set_snapshot_enabled(true); dap->set_vabc_enabled(true); dap->set_vabc_compression_param("none"); dap->set_cow_version(kCowVersionMajor); auto source_slot = fs_mgr_get_slot_suffix(); auto source_slot_number = SlotNumberForSlotSuffix(source_slot); auto target_slot = fs_mgr_get_other_slot_suffix(); auto target_slot_number = SlotNumberForSlotSuffix(target_slot); auto super_source = fs_mgr_get_super_partition_name(source_slot_number); // Get current partition information. PartitionOpener opener; auto source_metadata = ReadMetadata(opener, super_source, source_slot_number); if (!source_metadata) { std::cerr << "Could not read source partition metadata.\n"; return false; } auto system_source_name = "system" + source_slot; auto system_source = FindPartition(*source_metadata.get(), system_source_name); if (!system_source) { std::cerr << "Could not find system partition: " << system_source_name << ".\n"; return false; } auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source); // Since we only add copy operations, 64MB should be enough. auto system_update = manifest.mutable_partitions()->Add(); system_update->set_partition_name("system"); system_update->set_estimate_cow_size(64_MiB); system_update->mutable_new_partition_info()->set_size(system_source_size); if (!sm->CreateUpdateSnapshots(manifest)) { std::cerr << "Could not create update snapshots.\n"; return false; } // 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}, .partition_name = system_target_name, .partition_opener = &opener, .timeout_ms = 10s, }; auto writer = sm->OpenSnapshotWriter(clpp, {source_device}); 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)) { std::cerr << "Unable to add copy operation for block " << block << ".\n"; return false; } } if (!writer->Finalize()) { std::cerr << "Could not finalize COW for " << system_target_name << ".\n"; return false; } writer = nullptr; // Finished writing this partition, unmap. if (!sm->UnmapUpdateSnapshot(system_target_name)) { std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n"; return false; } // All snapshots have been written. if (!sm->FinishedSnapshotWrites(false /* wipe */)) { std::cerr << "Could not finalize snapshot writes.\n"; return false; } auto hal = hal::BootControlClient::WaitForService(); if (!hal) { std::cerr << "Could not find IBootControl HAL.\n"; return false; } auto cr = hal->SetActiveBootSlot(target_slot_number); if (!cr.IsOk()) { std::cerr << "Could not set active boot slot: " << cr.errMsg; return false; } std::cerr << "It is now safe to reboot your device. If using a physical device, make\n" << "sure that all physical partitions are flashed to both A and B slots.\n"; return true; } bool TestOtaHandler(int /* argc */, char** /* argv */) { auto sm = SnapshotManager::New(); if (!sm->BeginUpdate()) { std::cerr << "Error starting update.\n"; return false; } if (!CreateTestUpdate(sm.get())) { sm->CancelUpdate(); return false; } return true; } #endif static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = { // clang-format off {"dump", DumpCmdHandler}, {"merge", MergeCmdHandler}, {"map", MapCmdHandler}, #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG {"test-blank-ota", TestOtaHandler}, #endif {"unmap", UnmapCmdHandler}, // clang-format on }; Loading Loading
fs_mgr/libsnapshot/Android.bp +16 −0 Original line number Diff line number Diff line Loading @@ -324,6 +324,22 @@ cc_binary { "libstatslog", "libutils", ], header_libs: [ "libstorage_literals_headers", ], product_variables: { debuggable: { cppflags: [ "-DSNAPSHOTCTL_USERDEBUG_OR_ENG", ], shared_libs: [ "android.hardware.boot@1.0", "android.hardware.boot@1.1", "android.hardware.boot-V1-ndk", "libboot_control_client", ], }, }, } cc_test { Loading
fs_mgr/libsnapshot/snapshotctl.cpp +143 −0 Original line number Diff line number Diff line Loading @@ -25,9 +25,27 @@ #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <fs_mgr.h> #include <fs_mgr_dm_linear.h> #include <fstab/fstab.h> #include <liblp/builder.h> #include <libsnapshot/cow_format.h> #include <libsnapshot/snapshot.h> #include <storage_literals/storage_literals.h> #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG #include <BootControlClient.h> #endif using namespace std::chrono_literals; using namespace std::string_literals; using namespace android::storage_literals; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::FindPartition; using android::fs_mgr::GetPartitionSize; using android::fs_mgr::PartitionOpener; using android::fs_mgr::ReadMetadata; using android::fs_mgr::SlotNumberForSlotSuffix; int Usage() { std::cerr << "snapshotctl: Control snapshots.\n" Loading Loading @@ -67,11 +85,136 @@ bool MergeCmdHandler(int /*argc*/, char** argv) { return false; } #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG bool CreateTestUpdate(SnapshotManager* sm) { chromeos_update_engine::DeltaArchiveManifest manifest; // We only copy system, to simplify things. manifest.set_partial_update(true); auto dap = manifest.mutable_dynamic_partition_metadata(); dap->set_snapshot_enabled(true); dap->set_vabc_enabled(true); dap->set_vabc_compression_param("none"); dap->set_cow_version(kCowVersionMajor); auto source_slot = fs_mgr_get_slot_suffix(); auto source_slot_number = SlotNumberForSlotSuffix(source_slot); auto target_slot = fs_mgr_get_other_slot_suffix(); auto target_slot_number = SlotNumberForSlotSuffix(target_slot); auto super_source = fs_mgr_get_super_partition_name(source_slot_number); // Get current partition information. PartitionOpener opener; auto source_metadata = ReadMetadata(opener, super_source, source_slot_number); if (!source_metadata) { std::cerr << "Could not read source partition metadata.\n"; return false; } auto system_source_name = "system" + source_slot; auto system_source = FindPartition(*source_metadata.get(), system_source_name); if (!system_source) { std::cerr << "Could not find system partition: " << system_source_name << ".\n"; return false; } auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source); // Since we only add copy operations, 64MB should be enough. auto system_update = manifest.mutable_partitions()->Add(); system_update->set_partition_name("system"); system_update->set_estimate_cow_size(64_MiB); system_update->mutable_new_partition_info()->set_size(system_source_size); if (!sm->CreateUpdateSnapshots(manifest)) { std::cerr << "Could not create update snapshots.\n"; return false; } // 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}, .partition_name = system_target_name, .partition_opener = &opener, .timeout_ms = 10s, }; auto writer = sm->OpenSnapshotWriter(clpp, {source_device}); 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)) { std::cerr << "Unable to add copy operation for block " << block << ".\n"; return false; } } if (!writer->Finalize()) { std::cerr << "Could not finalize COW for " << system_target_name << ".\n"; return false; } writer = nullptr; // Finished writing this partition, unmap. if (!sm->UnmapUpdateSnapshot(system_target_name)) { std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n"; return false; } // All snapshots have been written. if (!sm->FinishedSnapshotWrites(false /* wipe */)) { std::cerr << "Could not finalize snapshot writes.\n"; return false; } auto hal = hal::BootControlClient::WaitForService(); if (!hal) { std::cerr << "Could not find IBootControl HAL.\n"; return false; } auto cr = hal->SetActiveBootSlot(target_slot_number); if (!cr.IsOk()) { std::cerr << "Could not set active boot slot: " << cr.errMsg; return false; } std::cerr << "It is now safe to reboot your device. If using a physical device, make\n" << "sure that all physical partitions are flashed to both A and B slots.\n"; return true; } bool TestOtaHandler(int /* argc */, char** /* argv */) { auto sm = SnapshotManager::New(); if (!sm->BeginUpdate()) { std::cerr << "Error starting update.\n"; return false; } if (!CreateTestUpdate(sm.get())) { sm->CancelUpdate(); return false; } return true; } #endif static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = { // clang-format off {"dump", DumpCmdHandler}, {"merge", MergeCmdHandler}, {"map", MapCmdHandler}, #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG {"test-blank-ota", TestOtaHandler}, #endif {"unmap", UnmapCmdHandler}, // clang-format on }; Loading