update_engine: Save and reload ping prefs from powerwash prefs.

Improve device active accuracy by updating prefs with last ping time.
Check if |kPrefsLastActivePingDay| and |kPrefsLastRollCallPingDay|
were preserved after powerwash and move to prefs if the key
does not already exist. Delete from powerwash to preserve user
privacy.

BUG=b:173145783
TEST=FEATURES=test emerge-{board} update_engine

Cq-Depend: chromium:2558521
Change-Id: I2f71d767ac90b5214c1f0e988137277e4fbe8ec3
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/system/update_engine/+/2558010
Tested-by: Vyshu Khota <vyshu@google.com>
Commit-Queue: Jae Hoon Kim <kimjae@chromium.org>
Reviewed-by: Jae Hoon Kim <kimjae@chromium.org>
diff --git a/cros/update_attempter.cc b/cros/update_attempter.cc
index cad7838..71b2a49 100644
--- a/cros/update_attempter.cc
+++ b/cros/update_attempter.cc
@@ -1715,12 +1715,31 @@
     }
   }
 
+  MoveToPrefs({kPrefsLastRollCallPingDay, kPrefsLastActivePingDay});
+
   SystemState::Get()->payload_state()->UpdateEngineStarted();
   StartP2PAtStartup();
 
   excluder_ = CreateExcluder();
 }
 
+void UpdateAttempter::MoveToPrefs(const vector<string>& keys) {
+  auto* powerwash_safe_prefs = SystemState::Get()->powerwash_safe_prefs();
+  for (const auto& key : keys) {
+    // Do not overwrite existing pref key with powerwash prefs.
+    if (!prefs_->Exists(key) && powerwash_safe_prefs->Exists(key)) {
+      string value;
+      if (!powerwash_safe_prefs->GetString(key, &value) ||
+          !prefs_->SetString(key, value)) {
+        PLOG(ERROR) << "Unable to add powerwash safe key " << key
+                    << " to prefs. Powerwash safe key will be deleted.";
+      }
+    }
+    // Delete keys regardless of operation success to preserve privacy.
+    powerwash_safe_prefs->Delete(key);
+  }
+}
+
 bool UpdateAttempter::StartP2PAtStartup() {
   if (!SystemState::Get()->p2p_manager()->IsP2PEnabled()) {
     LOG(INFO) << "Not starting p2p at startup since it's not enabled.";
diff --git a/cros/update_attempter.h b/cros/update_attempter.h
index aeb7f9b..6010484 100644
--- a/cros/update_attempter.h
+++ b/cros/update_attempter.h
@@ -290,6 +290,7 @@
   FRIEND_TEST(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable);
   FRIEND_TEST(UpdateAttempterTest, GetSuccessfulDlcIds);
   FRIEND_TEST(UpdateAttempterTest, QuickFixTokenWhenDeviceIsEnterpriseEnrolled);
+  FRIEND_TEST(UpdateAttempterTest, MoveToPrefs);
 
   // Returns the special flags to be added to ErrorCode values based on the
   // parameters used in the current update attempt.
@@ -387,6 +388,10 @@
   // on the |omaha_request_params_| object.
   void CalculateP2PParams(bool interactive);
 
+  // For each key, reads value from powerwash safe prefs and adds it to prefs
+  // if key doesnt already exist. Then deletes the powerwash safe keys.
+  void MoveToPrefs(const std::vector<std::string>& keys);
+
   // Starts P2P if it's enabled and there are files to actually share.
   // Called only at program startup. Returns true only if p2p was
   // started and housekeeping was performed.
diff --git a/cros/update_attempter_unittest.cc b/cros/update_attempter_unittest.cc
index b4fcdf2..a11e00c 100644
--- a/cros/update_attempter_unittest.cc
+++ b/cros/update_attempter_unittest.cc
@@ -2448,4 +2448,34 @@
   EXPECT_THAT(attempter_.GetSuccessfulDlcIds(), ElementsAre(dlc_2));
 }
 
+TEST_F(UpdateAttempterTest, MoveToPrefs) {
+  string key1 = kPrefsLastActivePingDay;
+  string key2 = kPrefsPingLastRollcall;
+
+  FakePrefs fake_prefs;
+  EXPECT_TRUE(fake_prefs.SetString(key2, "current-rollcall"));
+  FakeSystemState::Get()->set_prefs(&fake_prefs);
+
+  FakePrefs powerwash_safe_prefs;
+  EXPECT_TRUE(powerwash_safe_prefs.SetString(key1, "powerwash-last-active"));
+  EXPECT_TRUE(powerwash_safe_prefs.SetString(key2, "powerwash-last-rollcall"));
+  FakeSystemState::Get()->set_powerwash_safe_prefs(&powerwash_safe_prefs);
+
+  attempter_.Init();
+  attempter_.MoveToPrefs({key1, key2});
+
+  string pref_value_1;
+  fake_prefs.GetString(key1, &pref_value_1);
+  EXPECT_EQ(pref_value_1, "powerwash-last-active");
+  // Do not overwrite if value already exists.
+  string pref_value_2;
+  fake_prefs.GetString(key2, &pref_value_2);
+  EXPECT_EQ(pref_value_2, "current-rollcall");
+
+  // Make sure keys are deleted from powerwash safe prefs regardless of whether
+  // they are written to prefs.
+  EXPECT_FALSE(FakeSystemState::Get()->powerwash_safe_prefs()->Exists(key1));
+  EXPECT_FALSE(FakeSystemState::Get()->powerwash_safe_prefs()->Exists(key2));
+}
+
 }  // namespace chromeos_update_engine