update_engine: Enterprise channel downgrade

Powerwash and roll back when an enrolled user downgrades the channel:
- If the admin downgrades channel, check for ChannelDowngradebehavior
policy.
- If the user downgrades the channel, powerwash based on given boolean.

Add the "rollback" flag to the powerwash file to try to preserve some
data.

Note that this change is not affecting users yet: The
ChannelDowngradeBehavior policy is not available in DPanel and the UI
does not support chosing powerwash on channel downgrade for enrolled
users.

BUG=chromium:1122531
TEST=FEATURES=test emerge-amd64-generic update_engine
TEST=Set policy with YAPS and test on device

Change-Id: I2f02a6e752eed083b57484766f8e7ecc2eed7aca
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/system/update_engine/+/2397890
Tested-by: Miriam Polzer <mpolzer@google.com>
Commit-Queue: Miriam Polzer <mpolzer@google.com>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Jae Hoon Kim <kimjae@chromium.org>
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 04cfa73..4e421b0 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -532,6 +532,132 @@
 }
 
 TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableChannelButSameVersionTest) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "12345.0.0.0";
+  in.packages.push_back({.payload_urls = {"https://ChannelDownVersionUp"},
+                         .size = 1,
+                         .hash = kPayloadHashHex});
+  in.more_info_url = "http://more/info";
+
+  // Create a uniquely named test directory.
+  base::ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+
+  OmahaRequestParams params(&fake_system_state_);
+  fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
+  params.set_root(tempdir.GetPath().value());
+  params.set_current_channel("beta-channel");
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("12345.0.0.0");
+
+  fake_system_state_.set_request_params(&params);
+  InstallPlan install_plan;
+  EXPECT_TRUE(DoTest(in, "", &install_plan));
+  EXPECT_FALSE(install_plan.powerwash_required);
+  EXPECT_FALSE(install_plan.rollback_data_save_requested);
+}
+
+// On an enrolled device, the rollback data restore should be attempted when
+// doing a powerwash and channel downgrade.
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableChannelEnrolledDataRestore) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "12345.96.0.0";
+  in.packages.push_back({.payload_urls = {"https://ChannelDownEnrolled"},
+                         .size = 1,
+                         .hash = kPayloadHashHex});
+  in.more_info_url = "http://more/info";
+
+  // Create a uniquely named test directory.
+  base::ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+
+  OmahaRequestParams params(&fake_system_state_);
+  fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
+  params.set_root(tempdir.GetPath().value());
+  params.set_current_channel("beta-channel");
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("12347.48.0.0");
+
+  testing::NiceMock<policy::MockDevicePolicy> mock_device_policy;
+  EXPECT_CALL(mock_device_policy, IsEnterpriseEnrolled())
+      .WillOnce(Return(true));
+  fake_system_state_.set_device_policy(&mock_device_policy);
+
+  fake_system_state_.set_request_params(&params);
+  InstallPlan install_plan;
+  EXPECT_TRUE(DoTest(in, "", &install_plan));
+  EXPECT_TRUE(install_plan.rollback_data_save_requested);
+}
+
+// Never attempt rollback data restore if the device is not enrolled.
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableChannelUnenrolledNoDataRestore) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "12345.96.0.0";
+  in.packages.push_back({.payload_urls = {"https://ChannelDownEnrolled"},
+                         .size = 1,
+                         .hash = kPayloadHashHex});
+  in.more_info_url = "http://more/info";
+
+  // Create a uniquely named test directory.
+  base::ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+
+  OmahaRequestParams params(&fake_system_state_);
+  fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
+  params.set_root(tempdir.GetPath().value());
+  params.set_current_channel("beta-channel");
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("12347.48.0.0");
+
+  testing::NiceMock<policy::MockDevicePolicy> mock_device_policy;
+  EXPECT_CALL(mock_device_policy, IsEnterpriseEnrolled())
+      .WillOnce(Return(false));
+  fake_system_state_.set_device_policy(&mock_device_policy);
+
+  fake_system_state_.set_request_params(&params);
+  InstallPlan install_plan;
+  EXPECT_TRUE(DoTest(in, "", &install_plan));
+  EXPECT_FALSE(install_plan.rollback_data_save_requested);
+}
+
+// Never attempt rollback data restore if powerwash is not allowed.
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableChannelNoPowerwashNoDataRestore) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "12345.96.0.0";
+  in.packages.push_back(
+      {.payload_urls = {"https://URL"}, .size = 1, .hash = kPayloadHashHex});
+  in.more_info_url = "http://more/info";
+
+  // Create a uniquely named test directory.
+  base::ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+
+  OmahaRequestParams params(&fake_system_state_);
+  fake_system_state_.fake_hardware()->SetIsOfficialBuild(true);
+  params.set_root(tempdir.GetPath().value());
+  params.set_current_channel("beta-channel");
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", false, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("12347.48.0.0");
+
+  fake_system_state_.set_request_params(&params);
+  InstallPlan install_plan;
+  EXPECT_TRUE(DoTest(in, "", &install_plan));
+  EXPECT_FALSE(install_plan.rollback_data_save_requested);
+}
+
+TEST_F(OmahaResponseHandlerActionTest,
        ChangeToLessStableVersionAndChannelTest) {
   OmahaResponse in;
   in.update_exists = true;