Add support for new payload property headers to delay switching slots.
am: 02c4942cbf
Change-Id: Iddeb8c27625a3c0e444ca23b5a0625474f0e723a
diff --git a/common/constants.cc b/common/constants.cc
index c0a6e27..5941c93 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -57,6 +57,7 @@
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 @@
// 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 776e726..fefd08c 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -59,6 +59,7 @@
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 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 e08ec46..adae391 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -73,6 +73,9 @@
kFilesystemVerifierError = 47,
kUserCanceled = 48,
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 ad4aeeb..983d004 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -144,8 +144,10 @@
return "ErrorCode::kUserCanceled";
case ErrorCode::kNonCriticalUpdateInOOBE:
return "ErrorCode::kNonCriticalUpdateInOOBE";
- // 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 f6d0c74..abec2ad 100644
--- a/metrics_constants.h
+++ b/metrics_constants.h
@@ -95,6 +95,8 @@
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 5cff293..7e6b20f 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -39,6 +39,9 @@
case ErrorCode::kSuccess:
return metrics::AttemptResult::kUpdateSucceeded;
+ case ErrorCode::kUpdatedButNotActive:
+ return metrics::AttemptResult::kUpdateSucceededNotActive;
+
case ErrorCode::kDownloadTransferError:
return metrics::AttemptResult::kPayloadDownloadError;
@@ -210,6 +213,7 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ 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 c1afa44..d384e45 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1630,6 +1630,7 @@
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 b0dff31..45112d6 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -87,7 +87,10 @@
<< ", 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 551f8c2..5cdfbc1 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -119,6 +119,14 @@
// 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 27a9ed6..cedecda 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -82,6 +82,11 @@
}
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::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 1ec32c5..cff02b1 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -357,6 +357,7 @@
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;
@@ -633,6 +634,7 @@
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 7dcbeec..e716296 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -80,6 +80,13 @@
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(
@@ -192,10 +199,25 @@
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()) {
@@ -313,7 +335,6 @@
// Update succeeded.
WriteUpdateCompletedMarker();
prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
LOG(INFO) << "Update successfully applied, waiting to reboot.";
break;
@@ -351,6 +372,11 @@
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 989a97e..267f6e9 100644
--- a/update_engine_client_android.cc
+++ b/update_engine_client_android.cc
@@ -97,7 +97,10 @@
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 ffd378c..44f8821 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -134,6 +134,7 @@
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) << ")";