update_engine: Powerwash based on version

Powerwash after an update is currently enforced based on the channel: If
the new channel is more stable, powerwash happens. This may cause
unnecessary powerwash if the currently installed Chrome OS version is
old enough so that a normal update (e.g. 12817.68.0 -> 12817.76.0) can
take place.

Additionally decide whether a powerwash should take place based on the
new and old version number. Only powerwash if the new version number is
older than old version number.

BUG=chromium:1070563
TEST=FEATURES=test emerge-amd64-generic update_engine
channel change and update on test device

Change-Id: Ib211cf87711bde9f9c912395548124dcbb1194bb
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/system/update_engine/+/2162986
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 0ebf848..04cfa73 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -430,10 +430,11 @@
   EXPECT_EQ(in.version, install_plan.version);
 }
 
-TEST_F(OmahaResponseHandlerActionTest, ChangeToMoreStableChannelTest) {
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableVersionAndChannelTest) {
   OmahaResponse in;
   in.update_exists = true;
-  in.version = "a.b.c.d";
+  in.version = "1.0.0.0";
   in.packages.push_back({.payload_urls = {"https://MoreStableChannelTest"},
                          .size = 1,
                          .hash = kPayloadHashHex});
@@ -454,7 +455,7 @@
 #endif  // __ANDROID__
   EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
   params.UpdateDownloadChannel();
-  EXPECT_TRUE(params.ShouldPowerwash());
+  params.set_app_version("2.0.0.0");
 
   fake_system_state_.set_request_params(&params);
   InstallPlan install_plan;
@@ -462,10 +463,79 @@
   EXPECT_TRUE(install_plan.powerwash_required);
 }
 
-TEST_F(OmahaResponseHandlerActionTest, ChangeToLessStableChannelTest) {
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableVersionAndChannelPowerwashNotAllowedTest) {
   OmahaResponse in;
   in.update_exists = true;
-  in.version = "a.b.c.d";
+  in.version = "1.0.0.0";
+  in.packages.push_back({.payload_urls = {"https://MoreStableChannelTest"},
+                         .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("canary-channel");
+  // The |ImageProperties| in Android uses prefs to store
+  // |MutableImageProperties|.
+#ifdef __ANDROID__
+  EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, true))
+      .WillOnce(Return(true));
+#endif  // __ANDROID__
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", false, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("2.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);
+}
+
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToMoreStableChannelButNewerVersionTest) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "12345.96.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");
+  // The |ImageProperties| in Android uses prefs to store
+  // |MutableImageProperties|.
+#ifdef __ANDROID__
+  EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, true))
+      .WillOnce(Return(true));
+#endif  // __ANDROID__
+  EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
+  params.UpdateDownloadChannel();
+  params.set_app_version("12345.48.0.0");
+
+  fake_system_state_.set_request_params(&params);
+  InstallPlan install_plan;
+  EXPECT_TRUE(DoTest(in, "", &install_plan));
+  EXPECT_FALSE(install_plan.powerwash_required);
+}
+
+TEST_F(OmahaResponseHandlerActionTest,
+       ChangeToLessStableVersionAndChannelTest) {
+  OmahaResponse in;
+  in.update_exists = true;
+  in.version = "2.0.0.0";
   in.packages.push_back({.payload_urls = {"https://LessStableChannelTest"},
                          .size = 15,
                          .hash = kPayloadHashHex});
@@ -486,7 +556,7 @@
 #endif  // __ANDROID__
   EXPECT_TRUE(params.SetTargetChannel("canary-channel", false, nullptr));
   params.UpdateDownloadChannel();
-  EXPECT_FALSE(params.ShouldPowerwash());
+  params.set_app_version("1.0.0.0");
 
   fake_system_state_.set_request_params(&params);
   InstallPlan install_plan;