libsnapshot: Add prolog to RemoveAllUpdateStates.
Add an optional prolog arg (function<bool()>) that is invoked before snapshots are deleted and update state set to none. This allows update_engine to delete markers before deleting snapshots to avoid depending on the erroneous markers. Otherwise, if update_engine delete markers after libsnapshot deletes update states, the device could technically get into a state where update_engine thinks the update has been applied, but snapshots are gone. Bug: 147696014 Test: libsnapshot_test Change-Id: I71bfc04a81ea4f94b3072558be50d2f80565113e
This commit is contained in:
parent
6d2a79839f
commit
ad74121bda
2 changed files with 30 additions and 19 deletions
|
|
@ -169,7 +169,8 @@ class SnapshotManager final {
|
|||
//
|
||||
// The optional callback allows the caller to periodically check the
|
||||
// progress with GetUpdateState().
|
||||
UpdateState ProcessUpdateState(const std::function<void()>& callback = {});
|
||||
UpdateState ProcessUpdateState(const std::function<void()>& callback = {},
|
||||
const std::function<bool()>& before_cancel = {});
|
||||
|
||||
public:
|
||||
// Initiate the merge if necessary, then wait for the merge to finish.
|
||||
|
|
@ -179,7 +180,8 @@ class SnapshotManager final {
|
|||
// - Unverified if called on the source slot
|
||||
// - MergeCompleted if merge is completed
|
||||
// - other states indicating an error has occurred
|
||||
UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr);
|
||||
UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr,
|
||||
const std::function<bool()>& before_cancel = {});
|
||||
|
||||
// Wait for the merge if rebooted into the new slot. Does NOT initiate a
|
||||
// merge. If the merge has not been initiated (but should be), wait.
|
||||
|
|
@ -375,14 +377,14 @@ class SnapshotManager final {
|
|||
|
||||
// Check for a cancelled or rolled back merge, returning true if such a
|
||||
// condition was detected and handled.
|
||||
bool HandleCancelledUpdate(LockedFile* lock);
|
||||
bool HandleCancelledUpdate(LockedFile* lock, const std::function<bool()>& before_cancel);
|
||||
|
||||
// Helper for HandleCancelledUpdate. Assumes booting from new slot.
|
||||
bool AreAllSnapshotsCancelled(LockedFile* lock);
|
||||
|
||||
// Remove artifacts created by the update process, such as snapshots, and
|
||||
// set the update state to None.
|
||||
bool RemoveAllUpdateState(LockedFile* lock);
|
||||
bool RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog = {});
|
||||
|
||||
// Interact with /metadata/ota.
|
||||
std::unique_ptr<LockedFile> OpenLock(int lock_flags);
|
||||
|
|
@ -437,8 +439,8 @@ class SnapshotManager final {
|
|||
// UpdateState::MergeCompleted
|
||||
// UpdateState::MergeFailed
|
||||
// UpdateState::MergeNeedsReboot
|
||||
UpdateState CheckMergeState();
|
||||
UpdateState CheckMergeState(LockedFile* lock);
|
||||
UpdateState CheckMergeState(const std::function<bool()>& before_cancel);
|
||||
UpdateState CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel);
|
||||
UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name);
|
||||
|
||||
// Interact with status files under /metadata/ota/snapshots.
|
||||
|
|
|
|||
|
|
@ -219,7 +219,12 @@ static bool RemoveFileIfExists(const std::string& path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
|
||||
bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog) {
|
||||
if (prolog && !prolog()) {
|
||||
LOG(WARNING) << "Can't RemoveAllUpdateState: prolog failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Removing all update state.";
|
||||
|
||||
#ifdef LIBSNAPSHOT_USE_CALLSTACK
|
||||
|
|
@ -789,9 +794,10 @@ bool SnapshotManager::QuerySnapshotStatus(const std::string& dm_name, std::strin
|
|||
// Note that when a merge fails, we will *always* try again to complete the
|
||||
// merge each time the device boots. There is no harm in doing so, and if
|
||||
// the problem was transient, we might manage to get a new outcome.
|
||||
UpdateState SnapshotManager::ProcessUpdateState(const std::function<void()>& callback) {
|
||||
UpdateState SnapshotManager::ProcessUpdateState(const std::function<void()>& callback,
|
||||
const std::function<bool()>& before_cancel) {
|
||||
while (true) {
|
||||
UpdateState state = CheckMergeState();
|
||||
UpdateState state = CheckMergeState(before_cancel);
|
||||
if (state == UpdateState::MergeFailed) {
|
||||
AcknowledgeMergeFailure();
|
||||
}
|
||||
|
|
@ -811,24 +817,25 @@ UpdateState SnapshotManager::ProcessUpdateState(const std::function<void()>& cal
|
|||
}
|
||||
}
|
||||
|
||||
UpdateState SnapshotManager::CheckMergeState() {
|
||||
UpdateState SnapshotManager::CheckMergeState(const std::function<bool()>& before_cancel) {
|
||||
auto lock = LockExclusive();
|
||||
if (!lock) {
|
||||
return UpdateState::MergeFailed;
|
||||
}
|
||||
|
||||
UpdateState state = CheckMergeState(lock.get());
|
||||
UpdateState state = CheckMergeState(lock.get(), before_cancel);
|
||||
if (state == UpdateState::MergeCompleted) {
|
||||
// Do this inside the same lock. Failures get acknowledged without the
|
||||
// lock, because flock() might have failed.
|
||||
AcknowledgeMergeSuccess(lock.get());
|
||||
} else if (state == UpdateState::Cancelled) {
|
||||
RemoveAllUpdateState(lock.get());
|
||||
RemoveAllUpdateState(lock.get(), before_cancel);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
UpdateState SnapshotManager::CheckMergeState(LockedFile* lock) {
|
||||
UpdateState SnapshotManager::CheckMergeState(LockedFile* lock,
|
||||
const std::function<bool()>& before_cancel) {
|
||||
UpdateState state = ReadUpdateState(lock);
|
||||
switch (state) {
|
||||
case UpdateState::None:
|
||||
|
|
@ -849,7 +856,7 @@ UpdateState SnapshotManager::CheckMergeState(LockedFile* lock) {
|
|||
// This is an edge case. Normally cancelled updates are detected
|
||||
// via the merge poll below, but if we never started a merge, we
|
||||
// need to also check here.
|
||||
if (HandleCancelledUpdate(lock)) {
|
||||
if (HandleCancelledUpdate(lock, before_cancel)) {
|
||||
return UpdateState::Cancelled;
|
||||
}
|
||||
return state;
|
||||
|
|
@ -1169,7 +1176,8 @@ bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock) {
|
||||
bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock,
|
||||
const std::function<bool()>& before_cancel) {
|
||||
auto slot = GetCurrentSlot();
|
||||
if (slot == Slot::Unknown) {
|
||||
return false;
|
||||
|
|
@ -1177,7 +1185,7 @@ bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock) {
|
|||
|
||||
// If all snapshots were reflashed, then cancel the entire update.
|
||||
if (AreAllSnapshotsCancelled(lock)) {
|
||||
RemoveAllUpdateState(lock);
|
||||
RemoveAllUpdateState(lock, before_cancel);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2391,7 +2399,8 @@ std::unique_ptr<AutoDevice> SnapshotManager::EnsureMetadataMounted() {
|
|||
return AutoUnmountDevice::New(device_->GetMetadataDir());
|
||||
}
|
||||
|
||||
UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report) {
|
||||
UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report,
|
||||
const std::function<bool()>& before_cancel) {
|
||||
{
|
||||
auto lock = LockExclusive();
|
||||
// Sync update state from file with bootloader.
|
||||
|
|
@ -2416,7 +2425,7 @@ UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_rep
|
|||
LOG(INFO) << "Waiting for any previous merge request to complete. "
|
||||
<< "This can take up to several minutes.";
|
||||
merge_stats.Resume();
|
||||
auto state = ProcessUpdateState(callback);
|
||||
auto state = ProcessUpdateState(callback, before_cancel);
|
||||
merge_stats.set_state(state);
|
||||
if (state == UpdateState::None) {
|
||||
LOG(INFO) << "Can't find any snapshot to merge.";
|
||||
|
|
@ -2439,7 +2448,7 @@ UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_rep
|
|||
// All other states can be handled by ProcessUpdateState.
|
||||
LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
|
||||
last_progress = 0;
|
||||
state = ProcessUpdateState(callback);
|
||||
state = ProcessUpdateState(callback, before_cancel);
|
||||
merge_stats.set_state(state);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue