libsnapshot: Collect more COW size data in snapshot merge stats.
Bug: 180535575
Test: manual test
Change-Id: Iea433aa5fd9390e462d5bf9841524ed345427af3
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index b4e92a2..e902fa4 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -46,7 +46,7 @@
SECOND_PHASE = 2;
}
-// Next: 12
+// Next: 13
message SnapshotStatus {
// Name of the snapshot. This is usually the name of the snapshotted
// logical partition; for example, "system_b".
@@ -105,6 +105,9 @@
// Compression algorithm (none, gz, or brotli).
string compression_algorithm = 11;
+
+ // Estimated COW size from OTA manifest.
+ uint64 estimated_cow_size = 12;
}
// Next: 8
@@ -159,7 +162,7 @@
MergePhase merge_phase = 6;
}
-// Next: 5
+// Next: 7
message SnapshotMergeReport {
// Status of the update after the merge attempts.
UpdateState state = 1;
@@ -173,4 +176,10 @@
// Whether compression/dm-user was used for any snapshots.
bool compression_enabled = 4;
+
+ // Total size used by COWs, including /data and the super partition.
+ uint64 total_cow_size_bytes = 5;
+
+ // Sum of the estimated COW fields in the OTA manifest.
+ uint64 estimated_cow_size_bytes = 6;
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 1e420cb..1cb966b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -26,7 +26,8 @@
MOCK_METHOD(bool, BeginUpdate, (), (override));
MOCK_METHOD(bool, CancelUpdate, (), (override));
MOCK_METHOD(bool, FinishedSnapshotWrites, (bool wipe), (override));
- MOCK_METHOD(bool, InitiateMerge, (uint64_t * cow_file_size), (override));
+ MOCK_METHOD(void, UpdateCowStats, (ISnapshotMergeStats * stats), (override));
+ MOCK_METHOD(bool, InitiateMerge, (), (override));
MOCK_METHOD(UpdateState, ProcessUpdateState,
(const std::function<bool()>& callback, const std::function<bool()>& before_cancel),
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index a79a86d..7e74fac 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -127,9 +127,14 @@
// may need to be merged before wiping.
virtual bool FinishedSnapshotWrites(bool wipe) = 0;
+ // Update an ISnapshotMergeStats object with statistics about COW usage.
+ // This should be called before the merge begins as otherwise snapshots
+ // may be deleted.
+ virtual void UpdateCowStats(ISnapshotMergeStats* stats) = 0;
+
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
- virtual bool InitiateMerge(uint64_t* cow_file_size = nullptr) = 0;
+ virtual bool InitiateMerge() = 0;
// Perform any necessary post-boot actions. This should be run soon after
// /data is mounted.
@@ -326,7 +331,8 @@
bool BeginUpdate() override;
bool CancelUpdate() override;
bool FinishedSnapshotWrites(bool wipe) override;
- bool InitiateMerge(uint64_t* cow_file_size = nullptr) override;
+ void UpdateCowStats(ISnapshotMergeStats* stats) override;
+ bool InitiateMerge() override;
UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
const std::function<bool()>& before_cancel = {}) override;
UpdateState GetUpdateState(double* progress = nullptr) override;
@@ -491,7 +497,8 @@
bool RemoveAllSnapshots(LockedFile* lock);
// List the known snapshot names.
- bool ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots);
+ bool ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots,
+ const std::string& suffix = "");
// Check for a cancelled or rolled back merge, returning true if such a
// condition was detected and handled.
@@ -679,6 +686,9 @@
friend std::ostream& operator<<(std::ostream& os, SnapshotManager::Slot slot);
Slot GetCurrentSlot();
+ // Return the suffix we expect snapshots to have.
+ std::string GetSnapshotSlotSuffix();
+
std::string ReadUpdateSourceSlotSuffix();
// Helper for RemoveAllSnapshots.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 96d2deb..3eeae64 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -30,7 +30,11 @@
virtual bool Start() = 0;
virtual void set_state(android::snapshot::UpdateState state, bool using_compression) = 0;
virtual void set_cow_file_size(uint64_t cow_file_size) = 0;
+ virtual void set_total_cow_size_bytes(uint64_t bytes) = 0;
+ virtual void set_estimated_cow_size_bytes(uint64_t bytes) = 0;
virtual uint64_t cow_file_size() = 0;
+ virtual uint64_t total_cow_size_bytes() = 0;
+ virtual uint64_t estimated_cow_size_bytes() = 0;
// Called when merge ends. Properly clean up permanent storage.
class Result {
@@ -54,6 +58,10 @@
void set_state(android::snapshot::UpdateState state, bool using_compression) override;
void set_cow_file_size(uint64_t cow_file_size) override;
uint64_t cow_file_size() override;
+ void set_total_cow_size_bytes(uint64_t bytes) override;
+ void set_estimated_cow_size_bytes(uint64_t bytes) override;
+ uint64_t total_cow_size_bytes() override;
+ uint64_t estimated_cow_size_bytes() override;
std::unique_ptr<Result> Finish() override;
private:
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 3365ceb..cc75db8 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -28,7 +28,8 @@
bool BeginUpdate() override;
bool CancelUpdate() override;
bool FinishedSnapshotWrites(bool wipe) override;
- bool InitiateMerge(uint64_t* cow_file_size = nullptr) override;
+ void UpdateCowStats(ISnapshotMergeStats* stats) override;
+ bool InitiateMerge() override;
UpdateState ProcessUpdateState(const std::function<bool()>& callback = {},
const std::function<bool()>& before_cancel = {}) override;
UpdateState GetUpdateState(double* progress = nullptr) override;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 6002043..5569da0 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -202,6 +202,10 @@
ret.snapshot_status.set_device_size(target_partition->size());
ret.snapshot_status.set_snapshot_size(target_partition->size());
+ if (update && update->has_estimate_cow_size()) {
+ ret.snapshot_status.set_estimated_cow_size(update->estimate_cow_size());
+ }
+
if (ret.snapshot_status.snapshot_size() == 0) {
LOG(INFO) << "Not creating snapshot for partition " << ret.snapshot_status.name();
ret.snapshot_status.set_cow_partition_size(0);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index ca4c265..60cef5e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -230,6 +230,15 @@
return Slot::Target;
}
+std::string SnapshotManager::GetSnapshotSlotSuffix() {
+ switch (GetCurrentSlot()) {
+ case Slot::Target:
+ return device_->GetSlotSuffix();
+ default:
+ return device_->GetOtherSlotSuffix();
+ }
+}
+
static bool RemoveFileIfExists(const std::string& path) {
std::string message;
if (!android::base::RemoveFileIfExists(path, &message)) {
@@ -624,7 +633,7 @@
return true;
}
-bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) {
+bool SnapshotManager::InitiateMerge() {
auto lock = LockExclusive();
if (!lock) return false;
@@ -691,7 +700,6 @@
std::vector<std::string> first_merge_group;
- uint64_t total_cow_file_size = 0;
DmTargetSnapshot::Status initial_target_values = {};
for (const auto& snapshot : snapshots) {
DmTargetSnapshot::Status current_status;
@@ -706,7 +714,6 @@
if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) {
return false;
}
- total_cow_file_size += snapshot_status.cow_file_size();
compression_enabled |= snapshot_status.compression_enabled();
if (DecideMergePhase(snapshot_status) == MergePhase::FIRST_PHASE) {
@@ -714,10 +721,6 @@
}
}
- if (cow_file_size) {
- *cow_file_size = total_cow_file_size;
- }
-
SnapshotUpdateStatus initial_status;
initial_status.set_state(UpdateState::Merging);
initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
@@ -1732,7 +1735,8 @@
return update_status.compression_enabled();
}
-bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots) {
+bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots,
+ const std::string& suffix) {
CHECK(lock);
auto dir_path = metadata_dir_ + "/snapshots"s;
@@ -1745,7 +1749,12 @@
struct dirent* dp;
while ((dp = readdir(dir.get())) != nullptr) {
if (dp->d_type != DT_REG) continue;
- snapshots->emplace_back(dp->d_name);
+
+ std::string name(dp->d_name);
+ if (!suffix.empty() && !android::base::EndsWith(name, suffix)) {
+ continue;
+ }
+ snapshots->emplace_back(std::move(name));
}
return true;
}
@@ -3565,5 +3574,34 @@
return MergePhase::SECOND_PHASE;
}
+void SnapshotManager::UpdateCowStats(ISnapshotMergeStats* stats) {
+ auto lock = LockExclusive();
+ if (!lock) return;
+
+ std::vector<std::string> snapshots;
+ if (!ListSnapshots(lock.get(), &snapshots, GetSnapshotSlotSuffix())) {
+ LOG(ERROR) << "Could not list snapshots";
+ return;
+ }
+
+ uint64_t cow_file_size = 0;
+ uint64_t total_cow_size = 0;
+ uint64_t estimated_cow_size = 0;
+ for (const auto& snapshot : snapshots) {
+ SnapshotStatus status;
+ if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) {
+ return;
+ }
+
+ cow_file_size += status.cow_file_size();
+ total_cow_size += status.cow_file_size() + status.cow_partition_size();
+ estimated_cow_size += status.estimated_cow_size();
+ }
+
+ stats->set_cow_file_size(cow_file_size);
+ stats->set_total_cow_size_bytes(total_cow_size);
+ stats->set_estimated_cow_size_bytes(estimated_cow_size);
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 513700d..35e2d92 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -98,6 +98,22 @@
return report_.cow_file_size();
}
+void SnapshotMergeStats::set_total_cow_size_bytes(uint64_t bytes) {
+ report_.set_total_cow_size_bytes(bytes);
+}
+
+void SnapshotMergeStats::set_estimated_cow_size_bytes(uint64_t bytes) {
+ report_.set_estimated_cow_size_bytes(bytes);
+}
+
+uint64_t SnapshotMergeStats::total_cow_size_bytes() {
+ return report_.total_cow_size_bytes();
+}
+
+uint64_t SnapshotMergeStats::estimated_cow_size_bytes() {
+ return report_.estimated_cow_size_bytes();
+}
+
class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result {
public:
SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report,
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 8a254c9..079e606 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -43,7 +43,7 @@
return false;
}
-bool SnapshotManagerStub::InitiateMerge(uint64_t*) {
+bool SnapshotManagerStub::InitiateMerge() {
LOG(ERROR) << __FUNCTION__ << " should never be called.";
return false;
}
@@ -127,6 +127,10 @@
void set_cow_file_size(uint64_t) override {}
uint64_t cow_file_size() override { return 0; }
std::unique_ptr<Result> Finish() override { return nullptr; }
+ void set_total_cow_size_bytes(uint64_t) override {}
+ void set_estimated_cow_size_bytes(uint64_t) override {}
+ uint64_t total_cow_size_bytes() override { return 0; }
+ uint64_t estimated_cow_size_bytes() override { return 0; }
};
ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
@@ -151,4 +155,8 @@
return false;
}
+void SnapshotManagerStub::UpdateCowStats(ISnapshotMergeStats*) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+}
+
} // namespace android::snapshot