Merge "Refactor update status management as protobuf"

This commit is contained in:
Treehugger Robot 2020-01-15 14:04:25 +00:00 committed by Gerrit Code Review
commit 5c63dc9322
4 changed files with 111 additions and 45 deletions

View file

@ -127,6 +127,7 @@ cc_library_static {
"include_test", "include_test",
], ],
srcs: [ srcs: [
"android/snapshot/snapshot.proto",
"test_helpers.cpp", "test_helpers.cpp",
], ],
shared_libs: [ shared_libs: [

View file

@ -85,3 +85,49 @@ message SnapshotStatus {
// This is non-zero when |state| == MERGING or MERGE_COMPLETED. // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
uint64 metadata_sectors = 8; uint64 metadata_sectors = 8;
} }
// Next: 8
enum UpdateState {
// No update or merge is in progress.
None = 0;
// An update is applying; snapshots may already exist.
Initiated = 1;
// An update is pending, but has not been successfully booted yet.
Unverified = 2;
// The kernel is merging in the background.
Merging = 3;
// Post-merge cleanup steps could not be completed due to a transient
// error, but the next reboot will finish any pending operations.
MergeNeedsReboot = 4;
// Merging is complete, and needs to be acknowledged.
MergeCompleted = 5;
// Merging failed due to an unrecoverable error.
MergeFailed = 6;
// The update was implicitly cancelled, either by a rollback or a flash
// operation via fastboot. This state can only be returned by WaitForMerge.
Cancelled = 7;
};
// Next: 5
message SnapshotUpdateStatus {
UpdateState state = 1;
// Total number of sectors allocated in the COW files before performing the
// merge operation. This field is used to keep track of the total number
// of sectors modified to monitor and show the progress of the merge during
// an update.
uint64 sectors_allocated = 2;
// Total number of sectors of all the snapshot devices.
uint64 total_sectors = 3;
// Sectors allocated for metadata in all the snapshot devices.
uint64 metadata_sectors = 4;
}

View file

@ -26,6 +26,7 @@
#include <vector> #include <vector>
#include <android-base/unique_fd.h> #include <android-base/unique_fd.h>
#include <android/snapshot/snapshot.pb.h>
#include <fs_mgr_dm_linear.h> #include <fs_mgr_dm_linear.h>
#include <libdm/dm.h> #include <libdm/dm.h>
#include <libfiemap/image_manager.h> #include <libfiemap/image_manager.h>
@ -80,35 +81,6 @@ enum class CreateResult : unsigned int {
NOT_CREATED, NOT_CREATED,
}; };
enum class UpdateState : unsigned int {
// No update or merge is in progress.
None,
// An update is applying; snapshots may already exist.
Initiated,
// An update is pending, but has not been successfully booted yet.
Unverified,
// The kernel is merging in the background.
Merging,
// Post-merge cleanup steps could not be completed due to a transient
// error, but the next reboot will finish any pending operations.
MergeNeedsReboot,
// Merging is complete, and needs to be acknowledged.
MergeCompleted,
// Merging failed due to an unrecoverable error.
MergeFailed,
// The update was implicitly cancelled, either by a rollback or a flash
// operation via fastboot. This state can only be returned by WaitForMerge.
Cancelled
};
std::ostream& operator<<(std::ostream& os, UpdateState state);
class SnapshotManager final { class SnapshotManager final {
using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams; using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
using IPartitionOpener = android::fs_mgr::IPartitionOpener; using IPartitionOpener = android::fs_mgr::IPartitionOpener;
@ -433,7 +405,9 @@ class SnapshotManager final {
// Interact with /metadata/ota/state. // Interact with /metadata/ota/state.
UpdateState ReadUpdateState(LockedFile* file); UpdateState ReadUpdateState(LockedFile* file);
SnapshotUpdateStatus ReadSnapshotUpdateStatus(LockedFile* file);
bool WriteUpdateState(LockedFile* file, UpdateState state); bool WriteUpdateState(LockedFile* file, UpdateState state);
bool WriteSnapshotUpdateStatus(LockedFile* file, const SnapshotUpdateStatus& status);
std::string GetStateFilePath() const; std::string GetStateFilePath() const;
// Helpers for merging. // Helpers for merging.

View file

@ -560,9 +560,26 @@ bool SnapshotManager::InitiateMerge() {
} }
} }
DmTargetSnapshot::Status initial_target_values = {};
for (const auto& snapshot : snapshots) {
DmTargetSnapshot::Status current_status;
if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) {
return false;
}
initial_target_values.sectors_allocated += current_status.sectors_allocated;
initial_target_values.total_sectors += current_status.total_sectors;
initial_target_values.metadata_sectors += current_status.metadata_sectors;
}
SnapshotUpdateStatus initial_status;
initial_status.set_state(UpdateState::Merging);
initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
initial_status.set_total_sectors(initial_target_values.total_sectors);
initial_status.set_metadata_sectors(initial_target_values.metadata_sectors);
// Point of no return - mark that we're starting a merge. From now on every // Point of no return - mark that we're starting a merge. From now on every
// snapshot must be a merge target. // snapshot must be a merge target.
if (!WriteUpdateState(lock.get(), UpdateState::Merging)) { if (!WriteSnapshotUpdateStatus(lock.get(), initial_status)) {
return false; return false;
} }
@ -1643,15 +1660,7 @@ std::unique_ptr<SnapshotManager::LockedFile> SnapshotManager::LockExclusive() {
return OpenLock(LOCK_EX); return OpenLock(LOCK_EX);
} }
UpdateState SnapshotManager::ReadUpdateState(LockedFile* lock) { static UpdateState UpdateStateFromString(const std::string& contents) {
CHECK(lock);
std::string contents;
if (!android::base::ReadFileToString(GetStateFilePath(), &contents)) {
PLOG(ERROR) << "Read state file failed";
return UpdateState::None;
}
if (contents.empty() || contents == "none") { if (contents.empty() || contents == "none") {
return UpdateState::None; return UpdateState::None;
} else if (contents == "initiated") { } else if (contents == "initiated") {
@ -1694,18 +1703,54 @@ std::ostream& operator<<(std::ostream& os, UpdateState state) {
} }
} }
UpdateState SnapshotManager::ReadUpdateState(LockedFile* lock) {
SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock);
return status.state();
}
SnapshotUpdateStatus SnapshotManager::ReadSnapshotUpdateStatus(LockedFile* lock) {
CHECK(lock);
SnapshotUpdateStatus status = {};
std::string contents;
if (!android::base::ReadFileToString(GetStateFilePath(), &contents)) {
PLOG(ERROR) << "Read state file failed";
status.set_state(UpdateState::None);
return status;
}
if (!status.ParseFromString(contents)) {
LOG(WARNING) << "Unable to parse state file as SnapshotUpdateStatus, using the old format";
// Try to rollback to legacy file to support devices that are
// currently using the old file format.
// TODO(b/147409432)
status.set_state(UpdateStateFromString(contents));
}
return status;
}
bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state) { bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state) {
SnapshotUpdateStatus status = {};
status.set_state(state);
return WriteSnapshotUpdateStatus(lock, status);
}
bool SnapshotManager::WriteSnapshotUpdateStatus(LockedFile* lock,
const SnapshotUpdateStatus& status) {
CHECK(lock); CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX); CHECK(lock->lock_mode() == LOCK_EX);
std::stringstream ss; std::string contents;
ss << state; if (!status.SerializeToString(&contents)) {
std::string contents = ss.str(); LOG(ERROR) << "Unable to serialize SnapshotUpdateStatus.";
if (contents.empty()) return false; return false;
}
#ifdef LIBSNAPSHOT_USE_HAL #ifdef LIBSNAPSHOT_USE_HAL
auto merge_status = MergeStatus::UNKNOWN; auto merge_status = MergeStatus::UNKNOWN;
switch (state) { switch (status.state()) {
// The needs-reboot and completed cases imply that /data and /metadata // The needs-reboot and completed cases imply that /data and /metadata
// can be safely wiped, so we don't report a merge status. // can be safely wiped, so we don't report a merge status.
case UpdateState::None: case UpdateState::None:
@ -1724,7 +1769,7 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state) {
default: default:
// Note that Cancelled flows to here - it is never written, since // Note that Cancelled flows to here - it is never written, since
// it only communicates a transient state to the caller. // it only communicates a transient state to the caller.
LOG(ERROR) << "Unexpected update status: " << state; LOG(ERROR) << "Unexpected update status: " << status.state();
break; break;
} }