diff options
author | Yifan Hong <elsk@google.com> | 2020-02-19 15:22:47 -0800 |
---|---|---|
committer | Yifan Hong <elsk@google.com> | 2020-03-05 08:48:56 -0800 |
commit | 1dcd1a64ed275e73c1663cc13a06a2032c0f33da (patch) | |
tree | 098b44d7ef6728fb7fc3ae46d5b7f8e71f3f4a8b | |
parent | 120c31651c8aacfd3bf06a9593e88b3dd15920a1 (diff) | |
download | update_engine-1dcd1a64ed275e73c1663cc13a06a2032c0f33da.tar.gz |
UpdateAttempterAndroid::Init initiates merge
On update_engine starts, schedule CleanupPreviousUpdateAction that calls
CleanupSuccessfulUpdate to do necessary cleanup as soon as possible.
In the good case, update_engine initiates merge when
sys.boot_completed, and clean up snapshots.
If the update is
rolled back or partitions are flashed, the following happens (on
a Virtual A/B device):
- UpdateAttempterAndroid::CleanupSuccessfulUpdate is called
- DynamicPartitionControlAndroid::CleanupSuccessfulUpdate is called
- SnapshotManager::InitiateMergeAndWait is called
- SnapshotManager::RemoveAllUpdateState(before_cancel) is called
- before_cancel is called,
DeltaPerformer::ResetUpdateProgress is called
- All update states in update_engine is reset.
- SnapshotManager proceeds to delete snapshots
- All update states in SnapshotManager is reset.
Hence, on an VAB device, when an update is rolled back or partitions
are flashed, the whole update needs to be re-applied
(while in A/B, it skips writing and directly start verifying hashes of
the target partitions because the update markers are still there).
Bug: 147696014
Test: apply OTA then reboot, inspect logs and do `snapshotctl dump`
Change-Id: I0fc5e7768dfb53e4fd474f2d8d85d2a1b615a88b
Merged-In: I0fc5e7768dfb53e4fd474f2d8d85d2a1b615a88b
-rw-r--r-- | client_library/include/update_engine/update_status.h | 1 | ||||
-rw-r--r-- | common/action.h | 10 | ||||
-rw-r--r-- | common/dynamic_partition_control_interface.h | 20 | ||||
-rw-r--r-- | common/dynamic_partition_control_stub.cc | 9 | ||||
-rw-r--r-- | common/dynamic_partition_control_stub.h | 5 | ||||
-rw-r--r-- | dynamic_partition_control_android.cc | 13 | ||||
-rw-r--r-- | dynamic_partition_control_android.h | 4 | ||||
-rw-r--r-- | mock_dynamic_partition_control.h | 5 | ||||
-rw-r--r-- | update_attempter_android.cc | 32 | ||||
-rw-r--r-- | update_attempter_android.h | 9 | ||||
-rw-r--r-- | update_status_utils.cc | 5 |
11 files changed, 112 insertions, 1 deletions
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h index 5a3dccf8..6490e27a 100644 --- a/client_library/include/update_engine/update_status.h +++ b/client_library/include/update_engine/update_status.h @@ -41,6 +41,7 @@ enum class UpdateStatus { // Broadcast this state when an update aborts because user preferences do not // allow updates, e.g. over cellular network. NEED_PERMISSION_TO_UPDATE = 10, + CLEANUP_PREVIOUS_UPDATE = 11, }; // Enum of bit-wise flags for controlling how updates are attempted. diff --git a/common/action.h b/common/action.h index 9e2f5ff6..c93e73cb 100644 --- a/common/action.h +++ b/common/action.h @@ -222,6 +222,16 @@ class Action : public AbstractAction { out_pipe_; }; +// An action that does nothing and completes with kSuccess immediately. +class NoOpAction : public AbstractAction { + public: + ~NoOpAction() override {} + void PerformAction() override { + processor_->ActionComplete(this, ErrorCode::kSuccess); + } + std::string Type() const override { return "NoOpAction"; } +}; + }; // namespace chromeos_update_engine #endif // UPDATE_ENGINE_COMMON_ACTION_H_ diff --git a/common/dynamic_partition_control_interface.h b/common/dynamic_partition_control_interface.h index 48cd9be1..8de9d76a 100644 --- a/common/dynamic_partition_control_interface.h +++ b/common/dynamic_partition_control_interface.h @@ -22,6 +22,8 @@ #include <memory> #include <string> +#include "update_engine/common/action.h" +#include "update_engine/common/cleanup_previous_update_action_delegate.h" #include "update_engine/common/error_code.h" #include "update_engine/update_metadata.pb.h" @@ -38,6 +40,9 @@ struct FeatureFlag { Value value_; }; +class BootControlInterface; +class PrefsInterface; + class DynamicPartitionControlInterface { public: virtual ~DynamicPartitionControlInterface() = default; @@ -79,6 +84,7 @@ class DynamicPartitionControlInterface { // this function to indicate writes to new partitions are done. virtual bool FinishUpdate() = 0; + // Deprecated. Use GetCleanupPreviousUpdateAction instead. // Before applying the next update, call this function to clean up previous // update files. This function blocks until delta files are merged into // current OS partitions and finished cleaning up. @@ -86,6 +92,20 @@ class DynamicPartitionControlInterface { // - If any error, but caller should retry after reboot, return kError. // - If any irrecoverable failures, return kDeviceCorrupted. virtual ErrorCode CleanupSuccessfulUpdate() = 0; + + // Get an action to clean up previous update. + // Return NoOpAction on non-Virtual A/B devices. + // Before applying the next update, run this action to clean up previous + // update files. This function blocks until delta files are merged into + // current OS partitions and finished cleaning up. + // - If successful, action completes with kSuccess. + // - If any error, but caller should retry after reboot, action completes with + // kError. + // - If any irrecoverable failures, action completes with kDeviceCorrupted. + virtual std::unique_ptr<AbstractAction> GetCleanupPreviousUpdateAction( + BootControlInterface* boot_control, + PrefsInterface* prefs, + CleanupPreviousUpdateActionDelegateInterface* delegate) = 0; }; } // namespace chromeos_update_engine diff --git a/common/dynamic_partition_control_stub.cc b/common/dynamic_partition_control_stub.cc index cc36c5c9..70d6768a 100644 --- a/common/dynamic_partition_control_stub.cc +++ b/common/dynamic_partition_control_stub.cc @@ -16,6 +16,7 @@ #include <stdint.h> +#include <memory> #include <string> #include <base/logging.h> @@ -56,4 +57,12 @@ ErrorCode DynamicPartitionControlStub::CleanupSuccessfulUpdate() { return ErrorCode::kError; } +std::unique_ptr<AbstractAction> +DynamicPartitionControlStub::GetCleanupPreviousUpdateAction( + BootControlInterface* boot_control, + PrefsInterface* prefs, + CleanupPreviousUpdateActionDelegateInterface* delegate) { + return std::make_unique<NoOpAction>(); +} + } // namespace chromeos_update_engine diff --git a/common/dynamic_partition_control_stub.h b/common/dynamic_partition_control_stub.h index 02575a13..92e99221 100644 --- a/common/dynamic_partition_control_stub.h +++ b/common/dynamic_partition_control_stub.h @@ -19,6 +19,7 @@ #include <stdint.h> +#include <memory> #include <string> #include "update_engine/common/dynamic_partition_control_interface.h" @@ -40,6 +41,10 @@ class DynamicPartitionControlStub : public DynamicPartitionControlInterface { bool FinishUpdate() override; ErrorCode CleanupSuccessfulUpdate() override; + std::unique_ptr<AbstractAction> GetCleanupPreviousUpdateAction( + BootControlInterface* boot_control, + PrefsInterface* prefs, + CleanupPreviousUpdateActionDelegateInterface* delegate) override; }; } // namespace chromeos_update_engine diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc index 938a75bc..84c2f78c 100644 --- a/dynamic_partition_control_android.cc +++ b/dynamic_partition_control_android.cc @@ -35,6 +35,7 @@ #include <libdm/dm.h> #include <libsnapshot/snapshot.h> +#include "update_engine/cleanup_previous_update_action.h" #include "update_engine/common/boot_control_interface.h" #include "update_engine/common/utils.h" #include "update_engine/dynamic_partition_utils.h" @@ -786,4 +787,16 @@ bool DynamicPartitionControlAndroid::DeleteSourcePartitions( return true; } +std::unique_ptr<AbstractAction> +DynamicPartitionControlAndroid::GetCleanupPreviousUpdateAction( + BootControlInterface* boot_control, + PrefsInterface* prefs, + CleanupPreviousUpdateActionDelegateInterface* delegate) { + if (!GetVirtualAbFeatureFlag().IsEnabled()) { + return std::make_unique<NoOpAction>(); + } + return std::make_unique<CleanupPreviousUpdateAction>( + prefs, boot_control, snapshot_.get(), delegate); +} + } // namespace chromeos_update_engine diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h index e7ae26b4..aff02966 100644 --- a/dynamic_partition_control_android.h +++ b/dynamic_partition_control_android.h @@ -46,6 +46,10 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface { uint64_t* required_size) override; bool FinishUpdate() override; ErrorCode CleanupSuccessfulUpdate() override; + std::unique_ptr<AbstractAction> GetCleanupPreviousUpdateAction( + BootControlInterface* boot_control, + PrefsInterface* prefs, + CleanupPreviousUpdateActionDelegateInterface* delegate) override; // Return the device for partition |partition_name| at slot |slot|. // |current_slot| should be set to the current active slot. diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h index 1237d763..b3e0c24d 100644 --- a/mock_dynamic_partition_control.h +++ b/mock_dynamic_partition_control.h @@ -44,6 +44,11 @@ class MockDynamicPartitionControl : public DynamicPartitionControlInterface { MOCK_METHOD0(GetVirtualAbFeatureFlag, FeatureFlag()); MOCK_METHOD0(FinishUpdate, bool()); MOCK_METHOD0(CleanupSuccessfulUpdate, ErrorCode()); + MOCK_METHOD3(GetCleanupPreviousUpdateAction, + std::unique_ptr<AbstractAction>( + BootControlInterface*, + PrefsInterface*, + CleanupPreviousUpdateActionDelegateInterface*)); }; class MockDynamicPartitionControlAndroid diff --git a/update_attempter_android.cc b/update_attempter_android.cc index 680bbafb..a8a59536 100644 --- a/update_attempter_android.cc +++ b/update_attempter_android.cc @@ -157,6 +157,7 @@ void UpdateAttempterAndroid::Init() { } else { SetStatusAndNotify(UpdateStatus::IDLE); UpdatePrefsAndReportUpdateMetricsOnReboot(); + ScheduleCleanupPreviousUpdate(); } } @@ -502,6 +503,11 @@ void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor, ErrorCode code) { LOG(INFO) << "Processing Done."; + if (status_ == UpdateStatus::CLEANUP_PREVIOUS_UPDATE) { + TerminateUpdateAndNotify(code); + return; + } + switch (code) { case ErrorCode::kSuccess: // Update succeeded. @@ -625,6 +631,12 @@ void UpdateAttempterAndroid::TerminateUpdateAndNotify(ErrorCode error_code) { return; } + if (status_ == UpdateStatus::CLEANUP_PREVIOUS_UPDATE) { + LOG(INFO) << "Terminating cleanup previous update."; + SetStatusAndNotify(UpdateStatus::IDLE); + return; + } + boot_control_->GetDynamicPartitionControl()->Cleanup(); download_progress_ = 0; @@ -944,4 +956,24 @@ int32_t UpdateAttempterAndroid::CleanupSuccessfulUpdate( return static_cast<int32_t>(error_code); } +void UpdateAttempterAndroid::ScheduleCleanupPreviousUpdate() { + // If a previous CleanupSuccessfulUpdate call has not finished, or an update + // is in progress, skip enqueueing the action. + if (processor_->IsRunning()) { + LOG(INFO) << "Already processing an update. CleanupPreviousUpdate should " + << "be done when the current update finishes."; + return; + } + LOG(INFO) << "Scheduling CleanupPreviousUpdateAction."; + auto action = + boot_control_->GetDynamicPartitionControl() + ->GetCleanupPreviousUpdateAction(boot_control_, prefs_, this); + processor_->EnqueueAction(std::move(action)); + processor_->set_delegate(this); + SetStatusAndNotify(UpdateStatus::CLEANUP_PREVIOUS_UPDATE); + processor_->StartProcessing(); +} + +void UpdateAttempterAndroid::OnCleanupProgressUpdate(double progress) {} + } // namespace chromeos_update_engine diff --git a/update_attempter_android.h b/update_attempter_android.h index c301e645..106e1171 100644 --- a/update_attempter_android.h +++ b/update_attempter_android.h @@ -47,7 +47,8 @@ class UpdateAttempterAndroid : public ServiceDelegateAndroidInterface, public ActionProcessorDelegate, public DownloadActionDelegate, - public PostinstallRunnerAction::DelegateInterface { + public PostinstallRunnerAction::DelegateInterface, + public CleanupPreviousUpdateActionDelegateInterface { public: using UpdateStatus = update_engine::UpdateStatus; @@ -101,6 +102,9 @@ class UpdateAttempterAndroid // PostinstallRunnerAction::DelegateInterface void ProgressUpdate(double progress) override; + // CleanupPreviousUpdateActionDelegateInterface + void OnCleanupProgressUpdate(double progress) override; + private: friend class UpdateAttempterAndroidTest; @@ -177,6 +181,9 @@ class UpdateAttempterAndroid DeltaArchiveManifest* manifest, brillo::ErrorPtr* error); + // Enqueue and run a CleanupPreviousUpdateAction. + void ScheduleCleanupPreviousUpdate(); + DaemonStateInterface* daemon_state_; // DaemonStateAndroid pointers. diff --git a/update_status_utils.cc b/update_status_utils.cc index cbc4f14b..11fd2995 100644 --- a/update_status_utils.cc +++ b/update_status_utils.cc @@ -46,6 +46,8 @@ const char* UpdateStatusToString(const UpdateStatus& status) { return update_engine::kUpdateStatusAttemptingRollback; case UpdateStatus::DISABLED: return update_engine::kUpdateStatusDisabled; + case UpdateStatus::CLEANUP_PREVIOUS_UPDATE: + return update_engine::kUpdateStatusCleanupPreviousUpdate; } NOTREACHED(); @@ -86,6 +88,9 @@ bool StringToUpdateStatus(const std::string& s, UpdateStatus* status) { } else if (s == update_engine::kUpdateStatusDisabled) { *status = UpdateStatus::DISABLED; return true; + } else if (s == update_engine::kUpdateStatusCleanupPreviousUpdate) { + *status = UpdateStatus::CLEANUP_PREVIOUS_UPDATE; + return true; } return false; } |