Merge remote-tracking branch 'aosp/upstream-master' into merge

Test: treehugger
Change-Id: I4984f03fa95a753fb17779451eb458f177432d4f
diff --git a/common/clock.cc b/common/clock.cc
index 05c495c..0821a56 100644
--- a/common/clock.cc
+++ b/common/clock.cc
@@ -20,11 +20,11 @@
 
 namespace chromeos_update_engine {
 
-base::Time Clock::GetWallclockTime() {
+base::Time Clock::GetWallclockTime() const {
   return base::Time::Now();
 }
 
-base::Time Clock::GetMonotonicTime() {
+base::Time Clock::GetMonotonicTime() const {
   struct timespec now_ts;
   if (clock_gettime(CLOCK_MONOTONIC_RAW, &now_ts) != 0) {
     // Avoid logging this as an error as call-sites may call this very
@@ -40,7 +40,7 @@
   return base::Time::FromTimeVal(now_tv);
 }
 
-base::Time Clock::GetBootTime() {
+base::Time Clock::GetBootTime() const {
   struct timespec now_ts;
   if (clock_gettime(CLOCK_BOOTTIME, &now_ts) != 0) {
     // Avoid logging this as an error as call-sites may call this very
diff --git a/common/clock.h b/common/clock.h
index 2f373a7..4021fa1 100644
--- a/common/clock.h
+++ b/common/clock.h
@@ -24,13 +24,11 @@
 // Implements a clock.
 class Clock : public ClockInterface {
  public:
-  Clock() {}
+  Clock() = default;
 
-  base::Time GetWallclockTime() override;
-
-  base::Time GetMonotonicTime() override;
-
-  base::Time GetBootTime() override;
+  base::Time GetWallclockTime() const override;
+  base::Time GetMonotonicTime() const override;
+  base::Time GetBootTime() const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Clock);
diff --git a/common/clock_interface.h b/common/clock_interface.h
index 2228983..176505d 100644
--- a/common/clock_interface.h
+++ b/common/clock_interface.h
@@ -32,21 +32,21 @@
   virtual ~ClockInterface() = default;
 
   // Gets the current time e.g. similar to base::Time::Now().
-  virtual base::Time GetWallclockTime() = 0;
+  virtual base::Time GetWallclockTime() const = 0;
 
   // Returns monotonic time since some unspecified starting point. It
   // is not increased when the system is sleeping nor is it affected
   // by NTP or the user changing the time.
   //
   // (This is a simple wrapper around clock_gettime(2) / CLOCK_MONOTONIC_RAW.)
-  virtual base::Time GetMonotonicTime() = 0;
+  virtual base::Time GetMonotonicTime() const = 0;
 
   // Returns monotonic time since some unspecified starting point. It
   // is increased when the system is sleeping but it's not affected
   // by NTP or the user changing the time.
   //
   // (This is a simple wrapper around clock_gettime(2) / CLOCK_BOOTTIME.)
-  virtual base::Time GetBootTime() = 0;
+  virtual base::Time GetBootTime() const = 0;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/common/constants.cc b/common/constants.cc
index 8883668..a9cf238 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -71,6 +71,7 @@
 const char kPrefsPingActive[] = "active";
 const char kPrefsPingLastActive[] = "date_last_active";
 const char kPrefsPingLastRollcall[] = "date_last_rollcall";
+const char kPrefsLastFp[] = "last-fp";
 const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
 const char kPrefsPreviousVersion[] = "previous-version";
 const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
diff --git a/common/constants.h b/common/constants.h
index f468b55..64447ce 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -73,6 +73,7 @@
 extern const char kPrefsPingActive[];
 extern const char kPrefsPingLastActive[];
 extern const char kPrefsPingLastRollcall[];
+extern const char kPrefsLastFp[];
 extern const char kPrefsPostInstallSucceeded[];
 extern const char kPrefsPreviousVersion[];
 extern const char kPrefsResumedUpdateFailures[];
diff --git a/common/daemon_state_interface.h b/common/daemon_state_interface.h
index 9509fa2..831e38b 100644
--- a/common/daemon_state_interface.h
+++ b/common/daemon_state_interface.h
@@ -19,7 +19,6 @@
 
 #include "update_engine/common/service_observer_interface.h"
 
-#include <memory>
 #include <set>
 
 namespace chromeos_update_engine {
@@ -42,6 +41,8 @@
 
  protected:
   DaemonStateInterface() = default;
+
+  DISALLOW_COPY_AND_ASSIGN(DaemonStateInterface);
 };
 
 }  // namespace chromeos_update_engine
diff --git a/common/download_action.h b/common/download_action.h
index c167c2d..18e5853 100644
--- a/common/download_action.h
+++ b/common/download_action.h
@@ -28,7 +28,6 @@
 #include "update_engine/common/boot_control_interface.h"
 #include "update_engine/common/http_fetcher.h"
 #include "update_engine/common/multi_range_http_fetcher.h"
-#include "update_engine/common/system_state.h"
 #include "update_engine/payload_consumer/delta_performer.h"
 #include "update_engine/payload_consumer/install_plan.h"
 
@@ -71,12 +70,11 @@
 
   // Takes ownership of the passed in HttpFetcher. Useful for testing.
   // A good calling pattern is:
-  // DownloadAction(prefs, boot_contol, hardware, system_state,
+  // DownloadAction(prefs, boot_contol, hardware,
   //                new WhateverHttpFetcher, false);
   DownloadAction(PrefsInterface* prefs,
                  BootControlInterface* boot_control,
                  HardwareInterface* hardware,
-                 SystemState* system_state,
                  HttpFetcher* http_fetcher,
                  bool interactive);
   ~DownloadAction() override;
@@ -141,14 +139,11 @@
   // Pointer to the current payload in install_plan_.payloads.
   InstallPlan::Payload* payload_{nullptr};
 
-  // SystemState required pointers.
+  // Required pointers.
   PrefsInterface* prefs_;
   BootControlInterface* boot_control_;
   HardwareInterface* hardware_;
 
-  // Global context for the system.
-  SystemState* system_state_;
-
   // Pointer to the MultiRangeHttpFetcher that does the http work.
   std::unique_ptr<MultiRangeHttpFetcher> http_fetcher_;
 
diff --git a/common/dynamic_partition_control_interface.h b/common/dynamic_partition_control_interface.h
index 855d6e8..4f46f74 100644
--- a/common/dynamic_partition_control_interface.h
+++ b/common/dynamic_partition_control_interface.h
@@ -26,6 +26,7 @@
 #include "update_engine/common/action.h"
 #include "update_engine/common/cleanup_previous_update_action_delegate.h"
 #include "update_engine/common/error_code.h"
+#include "update_engine/common/prefs_interface.h"
 #include "update_engine/payload_consumer/file_descriptor.h"
 #include "update_engine/update_metadata.pb.h"
 
@@ -54,7 +55,6 @@
 };
 
 class BootControlInterface;
-class PrefsInterface;
 
 class DynamicPartitionControlInterface {
  public:
diff --git a/common/excluder_interface.h b/common/excluder_interface.h
index 3985bba..1dfd227 100644
--- a/common/excluder_interface.h
+++ b/common/excluder_interface.h
@@ -26,6 +26,8 @@
 
 class PrefsInterface;
 
+// TODO(b/171829801): Move this interface to 'cros' directory. 'aosp' in no way
+// is using this. Not even the stub implementation.
 class ExcluderInterface {
  public:
   virtual ~ExcluderInterface() = default;
@@ -53,7 +55,7 @@
   ExcluderInterface() = default;
 };
 
-std::unique_ptr<ExcluderInterface> CreateExcluder(PrefsInterface* prefs);
+std::unique_ptr<ExcluderInterface> CreateExcluder();
 
 }  // namespace chromeos_update_engine
 
diff --git a/common/excluder_stub.cc b/common/excluder_stub.cc
index a251765..2b987fd 100644
--- a/common/excluder_stub.cc
+++ b/common/excluder_stub.cc
@@ -24,7 +24,7 @@
 
 namespace chromeos_update_engine {
 
-std::unique_ptr<ExcluderInterface> CreateExcluder(PrefsInterface* prefs) {
+std::unique_ptr<ExcluderInterface> CreateExcluder() {
   return std::make_unique<ExcluderStub>();
 }
 
diff --git a/common/fake_clock.h b/common/fake_clock.h
index 165ec4d..9c47b57 100644
--- a/common/fake_clock.h
+++ b/common/fake_clock.h
@@ -26,11 +26,11 @@
  public:
   FakeClock() {}
 
-  base::Time GetWallclockTime() override { return wallclock_time_; }
+  base::Time GetWallclockTime() const override { return wallclock_time_; }
 
-  base::Time GetMonotonicTime() override { return monotonic_time_; }
+  base::Time GetMonotonicTime() const override { return monotonic_time_; }
 
-  base::Time GetBootTime() override { return boot_time_; }
+  base::Time GetBootTime() const override { return boot_time_; }
 
   void SetWallclockTime(const base::Time& time) { wallclock_time_ = time; }
 
diff --git a/common/fake_prefs.cc b/common/fake_prefs.cc
index 73559c5..275667e 100644
--- a/common/fake_prefs.cc
+++ b/common/fake_prefs.cc
@@ -106,6 +106,22 @@
   return true;
 }
 
+bool FakePrefs::Delete(const string& key, const vector<string>& nss) {
+  bool success = Delete(key);
+  for (const auto& ns : nss) {
+    vector<string> ns_keys;
+    success = GetSubKeys(ns, &ns_keys) && success;
+    for (const auto& sub_key : ns_keys) {
+      auto last_key_seperator = sub_key.find_last_of(kKeySeparator);
+      if (last_key_seperator != string::npos &&
+          key == sub_key.substr(last_key_seperator + 1)) {
+        success = Delete(sub_key) && success;
+      }
+    }
+  }
+  return success;
+}
+
 bool FakePrefs::GetSubKeys(const string& ns, vector<string>* keys) const {
   for (const auto& pr : values_)
     if (pr.first.compare(0, ns.length(), ns) == 0)
diff --git a/common/fake_prefs.h b/common/fake_prefs.h
index b24ff4d..9af2550 100644
--- a/common/fake_prefs.h
+++ b/common/fake_prefs.h
@@ -48,6 +48,8 @@
 
   bool Exists(const std::string& key) const override;
   bool Delete(const std::string& key) override;
+  bool Delete(const std::string& key,
+              const std::vector<std::string>& nss) override;
 
   bool GetSubKeys(const std::string& ns,
                   std::vector<std::string>* keys) const override;
diff --git a/common/metrics_reporter_interface.h b/common/metrics_reporter_interface.h
index d7c5347..08636e3 100644
--- a/common/metrics_reporter_interface.h
+++ b/common/metrics_reporter_interface.h
@@ -25,19 +25,12 @@
 #include "update_engine/common/constants.h"
 #include "update_engine/common/error_code.h"
 #include "update_engine/common/metrics_constants.h"
-#include "update_engine/common/system_state.h"
 
 namespace chromeos_update_engine {
 
 enum class ServerToCheck;
 enum class CertificateCheckResult;
 
-namespace metrics {
-
-std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter();
-
-}  // namespace metrics
-
 class MetricsReporterInterface {
  public:
   virtual ~MetricsReporterInterface() = default;
@@ -92,7 +85,6 @@
   // if it's set, |kMetricCheckRollbackTargetVersion| reports the same, but only
   // if rollback is also allowed using enterprise policy.
   virtual void ReportUpdateCheckMetrics(
-      SystemState* system_state,
       metrics::CheckResult result,
       metrics::CheckReaction reaction,
       metrics::DownloadErrorCode download_error_code) = 0;
@@ -120,8 +112,7 @@
   // |kMetricAttemptTimeSinceLastAttemptUptimeMinutes| metrics are
   // automatically calculated and reported by maintaining persistent and
   // process-local state variables.
-  virtual void ReportUpdateAttemptMetrics(SystemState* system_state,
-                                          int attempt_number,
+  virtual void ReportUpdateAttemptMetrics(int attempt_number,
                                           PayloadType payload_type,
                                           base::TimeDelta duration,
                                           base::TimeDelta duration_uptime,
@@ -242,6 +233,12 @@
       bool has_time_restriction_policy, int time_to_update_days) = 0;
 };
 
+namespace metrics {
+
+std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter();
+
+}  // namespace metrics
+
 }  // namespace chromeos_update_engine
 
 #endif  // UPDATE_ENGINE_COMMON_METRICS_REPORTER_INTERFACE_H_
diff --git a/common/metrics_reporter_stub.h b/common/metrics_reporter_stub.h
index 1470aaa..80cf469 100644
--- a/common/metrics_reporter_stub.h
+++ b/common/metrics_reporter_stub.h
@@ -39,13 +39,11 @@
   void ReportDailyMetrics(base::TimeDelta os_age) override {}
 
   void ReportUpdateCheckMetrics(
-      SystemState* system_state,
       metrics::CheckResult result,
       metrics::CheckReaction reaction,
       metrics::DownloadErrorCode download_error_code) override {}
 
-  void ReportUpdateAttemptMetrics(SystemState* system_state,
-                                  int attempt_number,
+  void ReportUpdateAttemptMetrics(int attempt_number,
                                   PayloadType payload_type,
                                   base::TimeDelta duration,
                                   base::TimeDelta duration_uptime,
diff --git a/common/mock_metrics_reporter.h b/common/mock_metrics_reporter.h
index 922d1ee..1bb1e84 100644
--- a/common/mock_metrics_reporter.h
+++ b/common/mock_metrics_reporter.h
@@ -36,15 +36,13 @@
 
   MOCK_METHOD1(ReportDailyMetrics, void(base::TimeDelta os_age));
 
-  MOCK_METHOD4(ReportUpdateCheckMetrics,
-               void(SystemState* system_state,
-                    metrics::CheckResult result,
+  MOCK_METHOD3(ReportUpdateCheckMetrics,
+               void(metrics::CheckResult result,
                     metrics::CheckReaction reaction,
                     metrics::DownloadErrorCode download_error_code));
 
-  MOCK_METHOD8(ReportUpdateAttemptMetrics,
-               void(SystemState* system_state,
-                    int attempt_number,
+  MOCK_METHOD7(ReportUpdateAttemptMetrics,
+               void(int attempt_number,
                     PayloadType payload_type,
                     base::TimeDelta duration,
                     base::TimeDelta duration_uptime,
diff --git a/common/mock_prefs.h b/common/mock_prefs.h
index 62417a8..c91664e 100644
--- a/common/mock_prefs.h
+++ b/common/mock_prefs.h
@@ -41,6 +41,9 @@
 
   MOCK_CONST_METHOD1(Exists, bool(const std::string& key));
   MOCK_METHOD1(Delete, bool(const std::string& key));
+  MOCK_METHOD2(Delete,
+               bool(const std::string& key,
+                    const std::vector<std::string>& nss));
 
   MOCK_CONST_METHOD2(GetSubKeys,
                      bool(const std::string&, std::vector<std::string>*));
diff --git a/common/prefs.cc b/common/prefs.cc
index 615014f..84fe536 100644
--- a/common/prefs.cc
+++ b/common/prefs.cc
@@ -34,8 +34,6 @@
 
 namespace {
 
-const char kKeySeparator = '/';
-
 void DeleteEmptyDirectories(const base::FilePath& path) {
   base::FileEnumerator path_enum(
       path, false /* recursive */, base::FileEnumerator::DIRECTORIES);
@@ -43,7 +41,11 @@
        dir_path = path_enum.Next()) {
     DeleteEmptyDirectories(dir_path);
     if (base::IsDirectoryEmpty(dir_path))
+#if BASE_VER < 800000
       base::DeleteFile(dir_path, false);
+#else
+      base::DeleteFile(dir_path);
+#endif
   }
 }
 
@@ -112,6 +114,24 @@
   return true;
 }
 
+bool PrefsBase::Delete(const string& pref_key, const vector<string>& nss) {
+  // Delete pref key for platform.
+  bool success = Delete(pref_key);
+  // Delete pref key in each namespace.
+  for (const auto& ns : nss) {
+    vector<string> namespace_keys;
+    success = GetSubKeys(ns, &namespace_keys) && success;
+    for (const auto& key : namespace_keys) {
+      auto last_key_seperator = key.find_last_of(kKeySeparator);
+      if (last_key_seperator != string::npos &&
+          pref_key == key.substr(last_key_seperator + 1)) {
+        success = Delete(key) && success;
+      }
+    }
+  }
+  return success;
+}
+
 bool PrefsBase::GetSubKeys(const string& ns, vector<string>* keys) const {
   return storage_->GetSubKeys(ns, keys);
 }
@@ -194,7 +214,11 @@
 bool Prefs::FileStorage::DeleteKey(const string& key) {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
+#if BASE_VER < 800000
   TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
+#else
+  TEST_AND_RETURN_FALSE(base::DeleteFile(filename));
+#endif
   return true;
 }
 
diff --git a/common/prefs.h b/common/prefs.h
index 3fc1d89..d6ef668 100644
--- a/common/prefs.h
+++ b/common/prefs.h
@@ -74,6 +74,8 @@
 
   bool Exists(const std::string& key) const override;
   bool Delete(const std::string& key) override;
+  bool Delete(const std::string& pref_key,
+              const std::vector<std::string>& nss) override;
 
   bool GetSubKeys(const std::string& ns,
                   std::vector<std::string>* keys) const override;
diff --git a/common/prefs_interface.h b/common/prefs_interface.h
index 1311cb4..866d0ca 100644
--- a/common/prefs_interface.h
+++ b/common/prefs_interface.h
@@ -80,6 +80,12 @@
   // this key. Calling with non-existent keys does nothing.
   virtual bool Delete(const std::string& key) = 0;
 
+  // Deletes the pref key from platform and given namespace subdirectories.
+  // Keys are matched against end of pref keys in each namespace.
+  // Returns true if all deletes were successful.
+  virtual bool Delete(const std::string& pref_key,
+                      const std::vector<std::string>& nss) = 0;
+
   // Creates a key which is part of a sub preference.
   static std::string CreateSubKey(const std::vector<std::string>& ns_with_key);
 
@@ -98,6 +104,10 @@
   // anymore for future Set*() and Delete() method calls.
   virtual void RemoveObserver(const std::string& key,
                               ObserverInterface* observer) = 0;
+
+ protected:
+  // Key separator used to create sub key and get file names,
+  static const char kKeySeparator = '/';
 };
 
 }  // namespace chromeos_update_engine
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index 6dd26c0..a5f46e5 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -118,6 +118,23 @@
     for (const auto& key : keys0corner)
       EXPECT_TRUE(common_prefs_->Delete(key));
     EXPECT_FALSE(common_prefs_->Exists(key0corner));
+
+    // Test sub directory namespace.
+    const string kDlcPrefsSubDir = "foo-dir";
+    key1A = common_prefs_->CreateSubKey({kDlcPrefsSubDir, "dlc1", "keyA"});
+    EXPECT_TRUE(common_prefs_->SetString(key1A, "fp_1A"));
+    key1B = common_prefs_->CreateSubKey({kDlcPrefsSubDir, "dlc1", "keyB"});
+    EXPECT_TRUE(common_prefs_->SetString(key1B, "fp_1B"));
+    auto key2A = common_prefs_->CreateSubKey({kDlcPrefsSubDir, "dlc2", "keyA"});
+    EXPECT_TRUE(common_prefs_->SetString(key2A, "fp_A2"));
+
+    vector<string> fpKeys;
+    EXPECT_TRUE(common_prefs_->GetSubKeys(kDlcPrefsSubDir, &fpKeys));
+    EXPECT_EQ(fpKeys.size(), 3UL);
+    EXPECT_TRUE(common_prefs_->Delete(fpKeys[0]));
+    EXPECT_TRUE(common_prefs_->Delete(fpKeys[1]));
+    EXPECT_TRUE(common_prefs_->Delete(fpKeys[2]));
+    EXPECT_FALSE(common_prefs_->Exists(key1A));
   }
 
   PrefsInterface* common_prefs_;
@@ -423,6 +440,71 @@
   EXPECT_FALSE(base::PathExists(prefs_dir_.Append(name_space)));
 }
 
+TEST_F(PrefsTest, DeletePrefs) {
+  const string kPrefsSubDir = "foo-dir";
+  const string kFpKey = "kPrefFp";
+  const string kNotFpKey = "NotkPrefFp";
+  const string kOtherKey = "kPrefNotFp";
+
+  EXPECT_TRUE(prefs_.SetString(kFpKey, "3.000"));
+  EXPECT_TRUE(prefs_.SetString(kOtherKey, "not_fp_val"));
+
+  auto key1_fp = prefs_.CreateSubKey({kPrefsSubDir, "id-1", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key1_fp, "3.7"));
+  auto key_not_fp = prefs_.CreateSubKey({kPrefsSubDir, "id-1", kOtherKey});
+  EXPECT_TRUE(prefs_.SetString(key_not_fp, "not_fp_val"));
+  auto key2_fp = prefs_.CreateSubKey({kPrefsSubDir, "id-2", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key2_fp, "3.9"));
+  auto key3_fp = prefs_.CreateSubKey({kPrefsSubDir, "id-3", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key3_fp, "3.45"));
+
+  // Pref key does not match full subkey at end, should not delete.
+  auto key_middle_fp = prefs_.CreateSubKey({kPrefsSubDir, kFpKey, kOtherKey});
+  EXPECT_TRUE(prefs_.SetString(key_middle_fp, "not_fp_val"));
+  auto key_end_not_fp = prefs_.CreateSubKey({kPrefsSubDir, "id-1", kNotFpKey});
+  EXPECT_TRUE(prefs_.SetString(key_end_not_fp, "not_fp_val"));
+
+  // Delete key in platform and one namespace.
+  prefs_.Delete(kFpKey, {kPrefsSubDir});
+
+  EXPECT_FALSE(prefs_.Exists(kFpKey));
+  EXPECT_FALSE(prefs_.Exists(key1_fp));
+  EXPECT_FALSE(prefs_.Exists(key2_fp));
+  EXPECT_FALSE(prefs_.Exists(key3_fp));
+
+  // Check other keys are not deleted.
+  EXPECT_TRUE(prefs_.Exists(kOtherKey));
+  EXPECT_TRUE(prefs_.Exists(key_not_fp));
+  EXPECT_TRUE(prefs_.Exists(key_middle_fp));
+  EXPECT_TRUE(prefs_.Exists(key_end_not_fp));
+}
+
+TEST_F(PrefsTest, DeleteMultipleNamespaces) {
+  const string kFirstSubDir = "foo-dir";
+  const string kSecondarySubDir = "bar-dir";
+  const string kTertiarySubDir = "ter-dir";
+  const string kFpKey = "kPrefFp";
+
+  EXPECT_TRUE(prefs_.SetString(kFpKey, "3.000"));
+  // Set pref key in different namespaces.
+  auto key1_fp = prefs_.CreateSubKey({kFirstSubDir, "id-1", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key1_fp, "3.7"));
+  auto key2_fp = prefs_.CreateSubKey({kSecondarySubDir, "id-3", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key2_fp, "7.45"));
+  auto key3_fp = prefs_.CreateSubKey({kTertiarySubDir, "id-3", kFpKey});
+  EXPECT_TRUE(prefs_.SetString(key3_fp, "7.45"));
+
+  // Delete key in platform and given namespaces.
+  prefs_.Delete(kFpKey, {kFirstSubDir, kSecondarySubDir});
+
+  EXPECT_FALSE(prefs_.Exists(kFpKey));
+  EXPECT_FALSE(prefs_.Exists(key1_fp));
+  EXPECT_FALSE(prefs_.Exists(key2_fp));
+
+  // Tertiary namespace not given to delete. Key should still exist.
+  EXPECT_TRUE(prefs_.Exists(key3_fp));
+}
+
 class MockPrefsObserver : public PrefsInterface::ObserverInterface {
  public:
   MOCK_METHOD1(OnPrefSet, void(const string&));
diff --git a/common/system_state.cc b/common/system_state.cc
new file mode 100644
index 0000000..cff1dfe
--- /dev/null
+++ b/common/system_state.cc
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/common/system_state.h"
+
+namespace chromeos_update_engine {
+
+SystemState* SystemState::g_pointer_ = nullptr;
+
+}  // namespace chromeos_update_engine
diff --git a/common/system_state.h b/common/system_state.h
index 7a67046..8a9c865 100644
--- a/common/system_state.h
+++ b/common/system_state.h
@@ -17,6 +17,13 @@
 #ifndef UPDATE_ENGINE_COMMON_SYSTEM_STATE_H_
 #define UPDATE_ENGINE_COMMON_SYSTEM_STATE_H_
 
+#include <memory>
+
+#include <base/logging.h>
+
+#include "update_engine/common/clock_interface.h"
+#include "update_engine/common/prefs_interface.h"
+
 namespace chromeos_update_manager {
 
 class UpdateManager;
@@ -35,7 +42,6 @@
 // any circular references in header file inclusion. Hence forward-declaring
 // the required classes.
 class BootControlInterface;
-class ClockInterface;
 class ConnectionManagerInterface;
 class DlcServiceInterface;
 class HardwareInterface;
@@ -44,20 +50,20 @@
 class P2PManager;
 class PayloadStateInterface;
 class PowerManagerInterface;
-class PrefsInterface;
 class UpdateAttempter;
 
 // An interface to global system context, including platform resources,
 // the current state of the system, high-level objects whose lifetime is same
 // as main, system interfaces, etc.
 // Carved out separately so it can be mocked for unit tests.
-// Currently it has only one method, but we should start migrating other
-// methods to use this as and when needed to unit test them.
-// TODO(jaysri): Consider renaming this to something like GlobalContext.
 class SystemState {
  public:
-  // Destructs this object.
-  virtual ~SystemState() {}
+  virtual ~SystemState() = default;
+
+  static SystemState* Get() {
+    CHECK(g_pointer_ != nullptr);
+    return g_pointer_;
+  }
 
   // Sets or gets the latest device policy.
   virtual void set_device_policy(const policy::DevicePolicy* device_policy) = 0;
@@ -113,6 +119,9 @@
 
   // Returns a pointer to the DlcServiceInterface singleton.
   virtual DlcServiceInterface* dlcservice() = 0;
+
+ protected:
+  static SystemState* g_pointer_;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/common/utils.cc b/common/utils.cc
index 1ac42dc..3a89c2a 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -52,7 +52,6 @@
 #include <base/strings/stringprintf.h>
 #include <brillo/data_encoding.h>
 
-#include "update_engine/common/clock_interface.h"
 #include "update_engine/common/constants.h"
 #include "update_engine/common/platform_constants.h"
 #include "update_engine/common/prefs_interface.h"