Generalize OverlayUserPrefStore

Allows the overlay to be any PersistentPrefStore, thereby allowing us to
use a PersistentPrefStoreClient to connect to a remote in-memory pref
store in the Mojo pref service instead of using a local one.

Bug: 719770
Change-Id: I992c416503ab6f115cbf3d98d658bc0911c4c0c7
Reviewed-on: https://chromium-review.googlesource.com/514842
Reviewed-by: Sam McNally <[email protected]>
Reviewed-by: Bernhard Bauer <[email protected]>
Commit-Queue: Johan Tibell <[email protected]>
Cr-Commit-Position: refs/heads/master@{#474906}
diff --git a/components/prefs/overlay_user_pref_store.cc b/components/prefs/overlay_user_pref_store.cc
index 48271fb..a4d21cd 100644
--- a/components/prefs/overlay_user_pref_store.cc
+++ b/components/prefs/overlay_user_pref_store.cc
@@ -9,15 +9,48 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
+#include "components/prefs/in_memory_pref_store.h"
 
-OverlayUserPrefStore::OverlayUserPrefStore(
-    PersistentPrefStore* underlay)
-    : underlay_(underlay) {
-  underlay_->AddObserver(this);
+// Allows us to monitor two pref stores and tell updates from them apart. It
+// essentially mimics a Callback for the Observer interface (e.g. it allows
+// binding additional arguments).
+class OverlayUserPrefStore::ObserverAdapter : public PrefStore::Observer {
+ public:
+  ObserverAdapter(bool overlay, OverlayUserPrefStore* parent)
+      : overlay_(overlay), parent_(parent) {}
+
+  // Methods of PrefStore::Observer.
+  void OnPrefValueChanged(const std::string& key) override {
+    parent_->OnPrefValueChanged(overlay_, key);
+  }
+  void OnInitializationCompleted(bool succeeded) override {
+    parent_->OnInitializationCompleted(overlay_, succeeded);
+  }
+
+ private:
+  // Is the update for the overlay?
+  const bool overlay_;
+  OverlayUserPrefStore* const parent_;
+};
+
+OverlayUserPrefStore::OverlayUserPrefStore(PersistentPrefStore* underlay)
+    : OverlayUserPrefStore(new InMemoryPrefStore(), underlay) {}
+
+OverlayUserPrefStore::OverlayUserPrefStore(PersistentPrefStore* overlay,
+                                           PersistentPrefStore* underlay)
+    : overlay_observer_(
+          base::MakeUnique<OverlayUserPrefStore::ObserverAdapter>(true, this)),
+      underlay_observer_(
+          base::MakeUnique<OverlayUserPrefStore::ObserverAdapter>(false, this)),
+      overlay_(overlay),
+      underlay_(underlay) {
+  DCHECK(overlay->IsInitializationComplete());
+  overlay_->AddObserver(overlay_observer_.get());
+  underlay_->AddObserver(underlay_observer_.get());
 }
 
 bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
-  return overlay_.GetValue(key, NULL);
+  return overlay_->GetValue(key, NULL);
 }
 
 void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
@@ -33,23 +66,24 @@
 }
 
 bool OverlayUserPrefStore::IsInitializationComplete() const {
-  return underlay_->IsInitializationComplete();
+  return underlay_->IsInitializationComplete() &&
+         overlay_->IsInitializationComplete();
 }
 
 bool OverlayUserPrefStore::GetValue(const std::string& key,
                                     const base::Value** result) const {
   // If the |key| shall NOT be stored in the overlay store, there must not
   // be an entry.
-  DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
+  DCHECK(ShallBeStoredInOverlay(key) || !overlay_->GetValue(key, NULL));
 
-  if (overlay_.GetValue(key, result))
+  if (overlay_->GetValue(key, result))
     return true;
   return underlay_->GetValue(key, result);
 }
 
 std::unique_ptr<base::DictionaryValue> OverlayUserPrefStore::GetValues() const {
   auto values = underlay_->GetValues();
-  auto overlay_values = overlay_.AsDictionaryValue();
+  auto overlay_values = overlay_->GetValues();
   for (const auto& key : overlay_names_set_) {
     std::unique_ptr<base::Value> out_value;
     overlay_values->Remove(key, &out_value);
@@ -65,7 +99,8 @@
   if (!ShallBeStoredInOverlay(key))
     return underlay_->GetMutableValue(key, result);
 
-  if (overlay_.GetValue(key, result))
+  written_overlay_names_.insert(key);
+  if (overlay_->GetMutableValue(key, result))
     return true;
 
   // Try to create copy of underlay if the overlay does not contain a value.
@@ -74,7 +109,8 @@
     return false;
 
   *result = underlay_value->DeepCopy();
-  overlay_.SetValue(key, base::WrapUnique(*result));
+  overlay_->SetValue(key, base::WrapUnique(*result),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
   return true;
 }
 
@@ -86,8 +122,8 @@
     return;
   }
 
-  if (overlay_.SetValue(key, std::move(value)))
-    ReportValueChanged(key, flags);
+  written_overlay_names_.insert(key);
+  overlay_->SetValue(key, std::move(value), flags);
 }
 
 void OverlayUserPrefStore::SetValueSilently(const std::string& key,
@@ -98,7 +134,8 @@
     return;
   }
 
-  overlay_.SetValue(key, std::move(value));
+  written_overlay_names_.insert(key);
+  overlay_->SetValueSilently(key, std::move(value), flags);
 }
 
 void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
@@ -107,8 +144,8 @@
     return;
   }
 
-  if (overlay_.RemoveValue(key))
-    ReportValueChanged(key, flags);
+  written_overlay_names_.insert(key);
+  overlay_->RemoveValue(key, flags);
 }
 
 bool OverlayUserPrefStore::ReadOnly() const {
@@ -121,7 +158,7 @@
 
 PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
   // We do not read intentionally.
-  OnInitializationCompleted(true);
+  OnInitializationCompleted(/* overlay */ false, true);
   return PersistentPrefStore::PREF_READ_ERROR_NONE;
 }
 
@@ -129,7 +166,7 @@
     ReadErrorDelegate* error_delegate_raw) {
   std::unique_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
   // We do not read intentionally.
-  OnInitializationCompleted(true);
+  OnInitializationCompleted(/* overlay */ false, true);
 }
 
 void OverlayUserPrefStore::CommitPendingWrite() {
@@ -147,16 +184,6 @@
     observer.OnPrefValueChanged(key);
 }
 
-void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
-  if (!overlay_.GetValue(key, NULL))
-    ReportValueChanged(key, DEFAULT_PREF_WRITE_FLAGS);
-}
-
-void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
-  for (PrefStore::Observer& observer : observers_)
-    observer.OnInitializationCompleted(succeeded);
-}
-
 void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
   DCHECK(!key.empty()) << "Key is empty";
   DCHECK(overlay_names_set_.find(key) == overlay_names_set_.end())
@@ -165,11 +192,32 @@
 }
 
 void OverlayUserPrefStore::ClearMutableValues() {
-  overlay_.Clear();
+  for (const auto& key : written_overlay_names_) {
+    overlay_->RemoveValue(key, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  }
 }
 
 OverlayUserPrefStore::~OverlayUserPrefStore() {
-  underlay_->RemoveObserver(this);
+  overlay_->RemoveObserver(overlay_observer_.get());
+  underlay_->RemoveObserver(underlay_observer_.get());
+}
+
+void OverlayUserPrefStore::OnPrefValueChanged(bool overlay,
+                                              const std::string& key) {
+  if (overlay) {
+    ReportValueChanged(key, DEFAULT_PREF_WRITE_FLAGS);
+  } else {
+    if (!overlay_->GetValue(key, NULL))
+      ReportValueChanged(key, DEFAULT_PREF_WRITE_FLAGS);
+  }
+}
+
+void OverlayUserPrefStore::OnInitializationCompleted(bool overlay,
+                                                     bool succeeded) {
+  if (!IsInitializationComplete())
+    return;
+  for (PrefStore::Observer& observer : observers_)
+    observer.OnInitializationCompleted(succeeded);
 }
 
 bool OverlayUserPrefStore::ShallBeStoredInOverlay(