Merge "Refactor update status management as protobuf"

am: 5c63dc9322

Change-Id: I9a995365cbbf354a8f3da09f1d900d9e52b5e4a9
This commit is contained in:
Alessio Balsini 2020-01-15 06:07:46 -08:00 committed by android-build-merger
commit 122035fd3a
4 changed files with 111 additions and 45 deletions

View file

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

View file

@ -85,3 +85,49 @@ message SnapshotStatus {
// This is non-zero when |state| == MERGING or MERGE_COMPLETED.
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 <android-base/unique_fd.h>
#include <android/snapshot/snapshot.pb.h>
#include <fs_mgr_dm_linear.h>
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
@ -80,35 +81,6 @@ enum class CreateResult : unsigned int {
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 {
using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
using IPartitionOpener = android::fs_mgr::IPartitionOpener;
@ -433,7 +405,9 @@ class SnapshotManager final {
// Interact with /metadata/ota/state.
UpdateState ReadUpdateState(LockedFile* file);
SnapshotUpdateStatus ReadSnapshotUpdateStatus(LockedFile* file);
bool WriteUpdateState(LockedFile* file, UpdateState state);
bool WriteSnapshotUpdateStatus(LockedFile* file, const SnapshotUpdateStatus& status);
std::string GetStateFilePath() const;
// 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
// snapshot must be a merge target.
if (!WriteUpdateState(lock.get(), UpdateState::Merging)) {
if (!WriteSnapshotUpdateStatus(lock.get(), initial_status)) {
return false;
}
@ -1643,15 +1660,7 @@ std::unique_ptr<SnapshotManager::LockedFile> SnapshotManager::LockExclusive() {
return OpenLock(LOCK_EX);
}
UpdateState SnapshotManager::ReadUpdateState(LockedFile* lock) {
CHECK(lock);
std::string contents;
if (!android::base::ReadFileToString(GetStateFilePath(), &contents)) {
PLOG(ERROR) << "Read state file failed";
return UpdateState::None;
}
static UpdateState UpdateStateFromString(const std::string& contents) {
if (contents.empty() || contents == "none") {
return UpdateState::None;
} 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) {
SnapshotUpdateStatus status = {};
status.set_state(state);
return WriteSnapshotUpdateStatus(lock, status);
}
bool SnapshotManager::WriteSnapshotUpdateStatus(LockedFile* lock,
const SnapshotUpdateStatus& status) {
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
std::stringstream ss;
ss << state;
std::string contents = ss.str();
if (contents.empty()) return false;
std::string contents;
if (!status.SerializeToString(&contents)) {
LOG(ERROR) << "Unable to serialize SnapshotUpdateStatus.";
return false;
}
#ifdef LIBSNAPSHOT_USE_HAL
auto merge_status = MergeStatus::UNKNOWN;
switch (state) {
switch (status.state()) {
// The needs-reboot and completed cases imply that /data and /metadata
// can be safely wiped, so we don't report a merge status.
case UpdateState::None:
@ -1724,7 +1769,7 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state) {
default:
// Note that Cancelled flows to here - it is never written, since
// it only communicates a transient state to the caller.
LOG(ERROR) << "Unexpected update status: " << state;
LOG(ERROR) << "Unexpected update status: " << status.state();
break;
}