update_engine: Add support for enterprise rollback powerwash
- Adds the additional flag "rollback" to the powerwash file
- This flag allows additional data to be preserved over a powerwash
- Adds tests
BUG=chromium:881341
TEST=unittests
Change-Id: I4487f4de856ea8d2d0255e8de4cd1ba0762a8e53
Reviewed-on: https://chromium-review.googlesource.com/1412683
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Zentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Sen Jiang <senj@chromium.org>
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 63346ce..3e5a66e 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -104,13 +104,15 @@
int GetPowerwashCount() const override { return powerwash_count_; }
- bool SchedulePowerwash() override {
+ bool SchedulePowerwash(bool is_rollback) override {
powerwash_scheduled_ = true;
+ is_rollback_powerwash_ = is_rollback;
return true;
}
bool CancelPowerwash() override {
powerwash_scheduled_ = false;
+ is_rollback_powerwash_ = false;
return true;
}
@@ -190,6 +192,10 @@
// Getters to verify state.
int GetMaxKernelKeyRollforward() const { return kernel_max_rollforward_; }
+ bool GetIsRollbackPowerwashScheduled() const {
+ return powerwash_scheduled_ && is_rollback_powerwash_;
+ }
+
private:
bool is_official_build_{true};
bool is_normal_boot_mode_{true};
@@ -207,6 +213,7 @@
int firmware_max_rollforward_{kFirmwareMaxRollforward};
int powerwash_count_{kPowerwashCountNotSet};
bool powerwash_scheduled_{false};
+ bool is_rollback_powerwash_{false};
int64_t build_timestamp_{0};
bool first_active_omaha_ping_sent_{false};
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index bbc8660..0140588 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -102,8 +102,9 @@
virtual int GetPowerwashCount() const = 0;
// Signals that a powerwash (stateful partition wipe) should be performed
- // after reboot.
- virtual bool SchedulePowerwash() = 0;
+ // after reboot. If |is_rollback| is true additional state is preserved
+ // during shutdown that can be restored after the powerwash.
+ virtual bool SchedulePowerwash(bool is_rollback) = 0;
// Cancel the powerwash operation scheduled to be performed on next boot.
virtual bool CancelPowerwash() = 0;
diff --git a/hardware_android.cc b/hardware_android.cc
index a8a479d..21d4659 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -152,8 +152,9 @@
return 0;
}
-bool HardwareAndroid::SchedulePowerwash() {
+bool HardwareAndroid::SchedulePowerwash(bool is_rollback) {
LOG(INFO) << "Scheduling a powerwash to BCB.";
+ LOG_IF(WARNING, is_rollback) << "is_rollback was true but isn't supported.";
string err;
if (!update_bootloader_message({"--wipe_data", "--reason=wipe_data_from_ota"},
&err)) {
diff --git a/hardware_android.h b/hardware_android.h
index 920b659..5b3c99d 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -48,7 +48,7 @@
bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override;
bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
int GetPowerwashCount() const override;
- bool SchedulePowerwash() override;
+ bool SchedulePowerwash(bool is_rollback) override;
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index c5933b5..8ef05b2 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -61,9 +61,13 @@
const char kPowerwashMarkerFile[] =
"/mnt/stateful_partition/factory_install_reset";
-// The contents of the powerwash marker file.
+// The contents of the powerwash marker file for the non-rollback case.
const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n";
+// The contents of the powerwas marker file for the rollback case.
+const char kRollbackPowerwashCommand[] =
+ "safe fast keepimg rollback reason=update_engine\n";
+
// UpdateManager config path.
const char* kConfigFilePath = "/etc/update_manager.conf";
@@ -222,12 +226,15 @@
return powerwash_count;
}
-bool HardwareChromeOS::SchedulePowerwash() {
+bool HardwareChromeOS::SchedulePowerwash(bool is_rollback) {
+ const char* powerwash_command =
+ is_rollback ? kRollbackPowerwashCommand : kPowerwashCommand;
bool result = utils::WriteFile(
- kPowerwashMarkerFile, kPowerwashCommand, strlen(kPowerwashCommand));
+ kPowerwashMarkerFile, powerwash_command, strlen(powerwash_command));
if (result) {
LOG(INFO) << "Created " << kPowerwashMarkerFile
- << " to powerwash on next reboot";
+ << " to powerwash on next reboot (is_rollback=" << is_rollback
+ << ")";
} else {
PLOG(ERROR) << "Error in creating powerwash marker file: "
<< kPowerwashMarkerFile;
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 5c66641..8829866 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -53,7 +53,7 @@
bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override;
bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
int GetPowerwashCount() const override;
- bool SchedulePowerwash() override;
+ bool SchedulePowerwash(bool is_rollback) override;
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 83d910f..a782b8f 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -59,7 +59,7 @@
// Currently we're always powerwashing when rolling back.
if (install_plan_.powerwash_required || install_plan_.is_rollback) {
- if (hardware_->SchedulePowerwash()) {
+ if (hardware_->SchedulePowerwash(install_plan_.is_rollback)) {
powerwash_scheduled_ = true;
} else {
return CompletePostinstall(ErrorCode::kPostinstallPowerwashError);
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index 8d461d5..caee5e2 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -255,6 +255,7 @@
// Since powerwash_required was false, this should not trigger a powerwash.
EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
+ EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
}
TEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
@@ -274,6 +275,7 @@
// Check that powerwash was scheduled.
EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
+ EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
}
TEST_F(PostinstallRunnerActionTest, RunAsRootRollbackTest) {
@@ -286,8 +288,9 @@
/*is_rollback=*/true);
EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
- // Check that powerwash was scheduled.
+ // Check that powerwash was scheduled and that it's a rollback powerwash.
EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
+ EXPECT_TRUE(fake_hardware_.GetIsRollbackPowerwashScheduled());
}
// Runs postinstall from a partition file that doesn't mount, so it should
@@ -299,6 +302,7 @@
// In case of failure, Postinstall should not signal a powerwash even if it
// was requested.
EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
+ EXPECT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
}
// Check that the failures from the postinstall script cause the action to