diff options
author | Sen Jiang <senj@google.com> | 2017-10-31 15:14:11 -0700 |
---|---|---|
committer | Sen Jiang <senj@google.com> | 2017-11-01 16:50:30 -0700 |
commit | fe5228282571154b51d3907cad4744e228e66a22 (patch) | |
tree | 0ba712bc0a948783ede564bd73d3f6268af3251e | |
parent | 54e6868331ac10558f8bcb25c5448097a548b268 (diff) |
Add support for new payload property headers to delay switching slots.
Set SWITCH_SLOT_ON_REBOOT=0 to skip marking new slot as active.
When ready to reboot to the new update, call applyPayload() again to
switch the slots, download will be skipped because it has already
finished, filesystem verification will always happen, and postinstall
can be skipped if it succeeded before for this update and
RUN_POST_INSTALL is set to 0.
Also removed reset update progress when update succeeded to support
reverting to current slot with resetStatus() without clearing download
progress. If the next update is a different payload then we will still
reset the progress on next update.
Bug: 35212183
Test: update_device.py --extra-headers 'SWITCH_SLOT_ON_REBOOT=0' ...
Merged-In: I52e2371ea4a9e6a6d026b4dd04bb1a60d95c9d5c
Change-Id: I52e2371ea4a9e6a6d026b4dd04bb1a60d95c9d5c
(cherry picked from commit e9685de187317c3bc92a2d63d3f4a40b9831f448)
-rw-r--r-- | common/constants.cc | 8 | ||||
-rw-r--r-- | common/constants.h | 3 | ||||
-rw-r--r-- | common/error_code.h | 1 | ||||
-rw-r--r-- | common/error_code_utils.cc | 6 | ||||
-rw-r--r-- | metrics_constants.h | 2 | ||||
-rw-r--r-- | metrics_utils.cc | 4 | ||||
-rw-r--r-- | payload_consumer/delta_performer.cc | 1 | ||||
-rw-r--r-- | payload_consumer/install_plan.cc | 5 | ||||
-rw-r--r-- | payload_consumer/install_plan.h | 8 | ||||
-rw-r--r-- | payload_consumer/postinstall_runner_action.cc | 19 | ||||
-rw-r--r-- | payload_state.cc | 2 | ||||
-rw-r--r-- | update_attempter_android.cc | 34 | ||||
-rw-r--r-- | update_engine_client_android.cc | 5 | ||||
-rw-r--r-- | update_manager/chromeos_policy.cc | 1 |
14 files changed, 87 insertions, 12 deletions
diff --git a/common/constants.cc b/common/constants.cc index c0a6e279..5941c93b 100644 --- a/common/constants.cc +++ b/common/constants.cc @@ -57,6 +57,7 @@ const char kPrefsP2PEnabled[] = "p2p-enabled"; const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp"; const char kPrefsP2PNumAttempts[] = "p2p-num-attempts"; const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number"; +const char kPrefsPostInstallSucceeded[] = "post-install-succeeded"; const char kPrefsPreviousVersion[] = "previous-version"; const char kPrefsResumedUpdateFailures[] = "resumed-update-failures"; const char kPrefsRollbackVersion[] = "rollback-version"; @@ -103,5 +104,12 @@ const char kPayloadPropertyPowerwash[] = "POWERWASH"; // This can be used to zero-rate OTA traffic by sending it over the correct // network. const char kPayloadPropertyNetworkId[] = "NETWORK_ID"; +// Set "SWITCH_SLOT_ON_REBOOT=0" to skip marking the updated partitions active. +// The default is 1 (always switch slot if update succeeded). +const char kPayloadPropertySwitchSlotOnReboot[] = "SWITCH_SLOT_ON_REBOOT"; +// Set "RUN_POST_INSTALL=0" to skip running post install, this will only be +// honored if we're resuming an update and post install has already succeeded. +// The default is 1 (always run post install). +const char kPayloadPropertyRunPostInstall[] = "RUN_POST_INSTALL"; } // namespace chromeos_update_engine diff --git a/common/constants.h b/common/constants.h index 776e726d..fefd08cd 100644 --- a/common/constants.h +++ b/common/constants.h @@ -59,6 +59,7 @@ extern const char kPrefsP2PEnabled[]; extern const char kPrefsP2PFirstAttemptTimestamp[]; extern const char kPrefsP2PNumAttempts[]; extern const char kPrefsPayloadAttemptNumber[]; +extern const char kPrefsPostInstallSucceeded[]; extern const char kPrefsPreviousVersion[]; extern const char kPrefsResumedUpdateFailures[]; extern const char kPrefsRollbackVersion[]; @@ -96,6 +97,8 @@ extern const char kPayloadPropertyAuthorization[]; extern const char kPayloadPropertyUserAgent[]; extern const char kPayloadPropertyPowerwash[]; extern const char kPayloadPropertyNetworkId[]; +extern const char kPayloadPropertySwitchSlotOnReboot[]; +extern const char kPayloadPropertyRunPostInstall[]; // A download source is any combination of protocol and server (that's of // interest to us when looking at UMA metrics) using which we may download diff --git a/common/error_code.h b/common/error_code.h index 3800bf0f..0b08005a 100644 --- a/common/error_code.h +++ b/common/error_code.h @@ -75,6 +75,7 @@ enum class ErrorCode : int { kNonCriticalUpdateInOOBE = 49, // kOmahaUpdateIgnoredOverCellular = 50, kPayloadTimestampError = 51, + kUpdatedButNotActive = 52, // VERY IMPORTANT! When adding new error codes: // diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc index 0a015eb2..313a15f8 100644 --- a/common/error_code_utils.cc +++ b/common/error_code_utils.cc @@ -146,8 +146,10 @@ string ErrorCodeToString(ErrorCode code) { return "ErrorCode::kNonCriticalUpdateInOOBE"; case ErrorCode::kPayloadTimestampError: return "ErrorCode::kPayloadTimestampError"; - // Don't add a default case to let the compiler warn about newly added - // error codes which should be added here. + case ErrorCode::kUpdatedButNotActive: + return "ErrorCode::kUpdatedButNotActive"; + // Don't add a default case to let the compiler warn about newly added + // error codes which should be added here. } return "Unknown error: " + base::UintToString(static_cast<unsigned>(code)); diff --git a/metrics_constants.h b/metrics_constants.h index f6d0c74e..abec2ad4 100644 --- a/metrics_constants.h +++ b/metrics_constants.h @@ -95,6 +95,8 @@ enum class AttemptResult { kPostInstallFailed, // The postinstall step failed. kAbnormalTermination, // The attempt ended abnormally. kUpdateCanceled, // Update canceled by the user. + kUpdateSucceededNotActive, // Update succeeded but the new slot is not + // active. kNumConstants, diff --git a/metrics_utils.cc b/metrics_utils.cc index 24212214..46530f07 100644 --- a/metrics_utils.cc +++ b/metrics_utils.cc @@ -39,6 +39,9 @@ metrics::AttemptResult GetAttemptResult(ErrorCode code) { case ErrorCode::kSuccess: return metrics::AttemptResult::kUpdateSucceeded; + case ErrorCode::kUpdatedButNotActive: + return metrics::AttemptResult::kUpdateSucceededNotActive; + case ErrorCode::kDownloadTransferError: return metrics::AttemptResult::kPayloadDownloadError; @@ -212,6 +215,7 @@ metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) { case ErrorCode::kFilesystemVerifierError: case ErrorCode::kUserCanceled: case ErrorCode::kPayloadTimestampError: + case ErrorCode::kUpdatedButNotActive: break; // Special flags. These can't happen (we mask them out above) but diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc index a35b41d3..3d567fa0 100644 --- a/payload_consumer/delta_performer.cc +++ b/payload_consumer/delta_performer.cc @@ -1638,6 +1638,7 @@ bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs, bool quick) { prefs->SetInt64(kPrefsManifestMetadataSize, -1); prefs->SetInt64(kPrefsManifestSignatureSize, -1); prefs->SetInt64(kPrefsResumedUpdateFailures, 0); + prefs->Delete(kPrefsPostInstallSucceeded); } return true; } diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc index b0dff31e..45112d6e 100644 --- a/payload_consumer/install_plan.cc +++ b/payload_consumer/install_plan.cc @@ -87,7 +87,10 @@ void InstallPlan::Dump() const { << ", url: " << download_url << payloads_str << partitions_str << ", hash_checks_mandatory: " << utils::ToString(hash_checks_mandatory) - << ", powerwash_required: " << utils::ToString(powerwash_required); + << ", powerwash_required: " << utils::ToString(powerwash_required) + << ", switch_slot_on_reboot: " + << utils::ToString(switch_slot_on_reboot) + << ", run_post_install: " << utils::ToString(run_post_install); } bool InstallPlan::LoadPartitionsFromSlots(BootControlInterface* boot_control) { diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h index 551f8c25..5cdfbc1c 100644 --- a/payload_consumer/install_plan.h +++ b/payload_consumer/install_plan.h @@ -119,6 +119,14 @@ struct InstallPlan { // False otherwise. bool powerwash_required{false}; + // True if the updated slot should be marked active on success. + // False otherwise. + bool switch_slot_on_reboot{true}; + + // True if the update should run its post-install step. + // False otherwise. + bool run_post_install{true}; + // If not blank, a base-64 encoded representation of the PEM-encoded // public key in the response. std::string public_key_rsa; diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc index 27a9ed61..cedecda9 100644 --- a/payload_consumer/postinstall_runner_action.cc +++ b/payload_consumer/postinstall_runner_action.cc @@ -82,6 +82,11 @@ void PostinstallRunnerAction::PerformAction() { } void PostinstallRunnerAction::PerformPartitionPostinstall() { + if (!install_plan_.run_post_install) { + LOG(INFO) << "Skipping post-install according to install plan."; + return CompletePostinstall(ErrorCode::kSuccess); + } + if (install_plan_.download_url.empty()) { LOG(INFO) << "Skipping post-install during rollback"; return CompletePostinstall(ErrorCode::kSuccess); @@ -331,15 +336,21 @@ void PostinstallRunnerAction::CompletePartitionPostinstall( void PostinstallRunnerAction::CompletePostinstall(ErrorCode error_code) { // We only attempt to mark the new slot as active if all the postinstall // steps succeeded. - if (error_code == ErrorCode::kSuccess && - !boot_control_->SetActiveBootSlot(install_plan_.target_slot)) { - error_code = ErrorCode::kPostinstallRunnerError; + if (error_code == ErrorCode::kSuccess) { + if (install_plan_.switch_slot_on_reboot) { + if (!boot_control_->SetActiveBootSlot(install_plan_.target_slot)) { + error_code = ErrorCode::kPostinstallRunnerError; + } + } else { + error_code = ErrorCode::kUpdatedButNotActive; + } } ScopedActionCompleter completer(processor_, this); completer.set_code(error_code); - if (error_code != ErrorCode::kSuccess) { + if (error_code != ErrorCode::kSuccess && + error_code != ErrorCode::kUpdatedButNotActive) { LOG(ERROR) << "Postinstall action failed."; // Undo any changes done to trigger Powerwash. diff --git a/payload_state.cc b/payload_state.cc index 54ced727..4992606e 100644 --- a/payload_state.cc +++ b/payload_state.cc @@ -358,6 +358,7 @@ void PayloadState::UpdateFailed(ErrorCode error) { case ErrorCode::kOmahaRequestXMLHasEntityDecl: case ErrorCode::kFilesystemVerifierError: case ErrorCode::kUserCanceled: + case ErrorCode::kUpdatedButNotActive: LOG(INFO) << "Not incrementing URL index or failure count for this error"; break; @@ -634,6 +635,7 @@ void PayloadState::CollectAndReportAttemptMetrics(ErrorCode code) { case metrics::AttemptResult::kPostInstallFailed: case metrics::AttemptResult::kAbnormalTermination: case metrics::AttemptResult::kUpdateCanceled: + case metrics::AttemptResult::kUpdateSucceededNotActive: case metrics::AttemptResult::kNumConstants: case metrics::AttemptResult::kUnset: break; diff --git a/update_attempter_android.cc b/update_attempter_android.cc index 08a5e581..82e3855f 100644 --- a/update_attempter_android.cc +++ b/update_attempter_android.cc @@ -81,6 +81,13 @@ bool LogAndSetError(brillo::ErrorPtr* error, return false; } +bool GetHeaderAsBool(const string& header, bool default_value) { + int value = 0; + if (base::StringToInt(header, &value) && (value == 0 || value == 1)) + return value == 1; + return default_value; +} + } // namespace UpdateAttempterAndroid::UpdateAttempterAndroid( @@ -193,10 +200,25 @@ bool UpdateAttempterAndroid::ApplyPayload( install_plan_.source_slot = boot_control_->GetCurrentSlot(); install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0; - int data_wipe = 0; install_plan_.powerwash_required = - base::StringToInt(headers[kPayloadPropertyPowerwash], &data_wipe) && - data_wipe != 0; + GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false); + + install_plan_.switch_slot_on_reboot = + GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true); + + install_plan_.run_post_install = true; + // Optionally skip post install if and only if: + // a) we're resuming + // b) post install has already succeeded before + // c) RUN_POST_INSTALL is set to 0. + if (install_plan_.is_resume && prefs_->Exists(kPrefsPostInstallSucceeded)) { + bool post_install_succeeded = false; + prefs_->GetBoolean(kPrefsPostInstallSucceeded, &post_install_succeeded); + if (post_install_succeeded) { + install_plan_.run_post_install = + GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true); + } + } NetworkId network_id = kDefaultNetworkId; if (!headers[kPayloadPropertyNetworkId].empty()) { @@ -314,7 +336,6 @@ void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor, // Update succeeded. WriteUpdateCompletedMarker(); prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0); - DeltaPerformer::ResetUpdateProgress(prefs_, false); LOG(INFO) << "Update successfully applied, waiting to reboot."; break; @@ -357,6 +378,11 @@ void UpdateAttempterAndroid::ActionCompleted(ActionProcessor* processor, if (type == DownloadAction::StaticType()) { download_progress_ = 0; } + if (type == PostinstallRunnerAction::StaticType()) { + bool succeeded = + code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive; + prefs_->SetBoolean(kPrefsPostInstallSucceeded, succeeded); + } if (code != ErrorCode::kSuccess) { // If an action failed, the ActionProcessor will cancel the whole thing. return; diff --git a/update_engine_client_android.cc b/update_engine_client_android.cc index 989a97e1..267f6e98 100644 --- a/update_engine_client_android.cc +++ b/update_engine_client_android.cc @@ -97,7 +97,10 @@ Status UpdateEngineClientAndroid::UECallback::onPayloadApplicationComplete( ErrorCode code = static_cast<ErrorCode>(error_code); LOG(INFO) << "onPayloadApplicationComplete(" << utils::ErrorCodeToString(code) << " (" << error_code << "))"; - client_->ExitWhenIdle(code == ErrorCode::kSuccess ? EX_OK : 1); + client_->ExitWhenIdle( + (code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive) + ? EX_OK + : 1); return Status::ok(); } diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc index 81a169fb..da043727 100644 --- a/update_manager/chromeos_policy.cc +++ b/update_manager/chromeos_policy.cc @@ -135,6 +135,7 @@ bool HandleErrorCode(ErrorCode err_code, int* url_num_error_p) { case ErrorCode::kOmahaRequestXMLHasEntityDecl: case ErrorCode::kFilesystemVerifierError: case ErrorCode::kUserCanceled: + case ErrorCode::kUpdatedButNotActive: LOG(INFO) << "Not changing URL index or failure count due to error " << chromeos_update_engine::utils::ErrorCodeToString(err_code) << " (" << static_cast<int>(err_code) << ")"; |