Merge "Refactor update status management as protobuf"
am: 5c63dc9322
Change-Id: I9a995365cbbf354a8f3da09f1d900d9e52b5e4a9
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index eadcecc..9e67c66 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -127,6 +127,7 @@
"include_test",
],
srcs: [
+ "android/snapshot/snapshot.proto",
"test_helpers.cpp",
],
shared_libs: [
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 629c3a4..a3a518d 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -85,3 +85,49 @@
// 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;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 6e613ba..61946f7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -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 @@
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 @@
// 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.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b79b65c..70a69a5 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -560,9 +560,26 @@
}
}
+ DmTargetSnapshot::Status initial_target_values = {};
+ for (const auto& snapshot : snapshots) {
+ DmTargetSnapshot::Status current_status;
+ if (!QuerySnapshotStatus(snapshot, nullptr, ¤t_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 @@
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 @@
}
}
+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 @@
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;
}