summaryrefslogtreecommitdiff
path: root/chromium/services/preferences
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-09-18 14:34:04 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-10-04 11:15:27 +0000
commite6430e577f105ad8813c92e75c54660c4985026e (patch)
tree88115e5d1fb471fea807111924dcccbeadbf9e4f /chromium/services/preferences
parent53d399fe6415a96ea6986ec0d402a9c07da72453 (diff)
downloadqtwebengine-chromium-e6430e577f105ad8813c92e75c54660c4985026e.tar.gz
BASELINE: Update Chromium to 61.0.3163.99
Change-Id: I8452f34574d88ca2b27af9bd56fc9ff3f16b1367 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/services/preferences')
-rw-r--r--chromium/services/preferences/BUILD.gn23
-rw-r--r--chromium/services/preferences/README.md82
-rw-r--r--chromium/services/preferences/local_state_manifest.json15
-rw-r--r--chromium/services/preferences/manifest.json6
-rw-r--r--chromium/services/preferences/persistent_pref_store_factory.cc51
-rw-r--r--chromium/services/preferences/persistent_pref_store_factory.h28
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl.cc116
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl.h9
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl_unittest.cc103
-rw-r--r--chromium/services/preferences/pref_service_factory_unittest.cc334
-rw-r--r--chromium/services/preferences/pref_store_consistency_unittest.cc916
-rw-r--r--chromium/services/preferences/pref_store_impl.cc (renamed from chromium/services/preferences/public/cpp/pref_store_impl.cc)49
-rw-r--r--chromium/services/preferences/pref_store_impl.h (renamed from chromium/services/preferences/public/cpp/pref_store_impl.h)25
-rw-r--r--chromium/services/preferences/pref_store_impl_unittest.cc305
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.cc218
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.h96
-rw-r--r--chromium/services/preferences/public/cpp/BUILD.gn7
-rw-r--r--chromium/services/preferences/public/cpp/DEPS1
-rw-r--r--chromium/services/preferences/public/cpp/dictionary_value_update.cc8
-rw-r--r--chromium/services/preferences/public/cpp/in_process_service_factory.cc107
-rw-r--r--chromium/services/preferences/public/cpp/in_process_service_factory.h56
-rw-r--r--chromium/services/preferences/public/cpp/lib/util.cc69
-rw-r--r--chromium/services/preferences/public/cpp/lib/util.h7
-rw-r--r--chromium/services/preferences/public/cpp/persistent_pref_store_client.cc229
-rw-r--r--chromium/services/preferences/public/cpp/persistent_pref_store_client.h28
-rw-r--r--chromium/services/preferences/public/cpp/pref_registry_serializer.cc14
-rw-r--r--chromium/services/preferences/public/cpp/pref_registry_serializer.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.cc72
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.h1
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_main.cc20
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_main.h18
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_adapter.cc40
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_adapter.h44
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client_mixin.cc20
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client_mixin.h7
-rw-r--r--chromium/services/preferences/public/cpp/tests/BUILD.gn1
-rw-r--r--chromium/services/preferences/public/cpp/tracked/configuration.h2
-rw-r--r--chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h2
-rw-r--r--chromium/services/preferences/public/interfaces/BUILD.gn1
-rw-r--r--chromium/services/preferences/public/interfaces/preferences.mojom116
-rw-r--r--chromium/services/preferences/public/interfaces/preferences_configuration.mojom62
-rw-r--r--chromium/services/preferences/scoped_pref_connection_builder.cc48
-rw-r--r--chromium/services/preferences/scoped_pref_connection_builder.h24
-rw-r--r--chromium/services/preferences/shared_pref_registry.cc190
-rw-r--r--chromium/services/preferences/shared_pref_registry.h80
-rw-r--r--chromium/services/preferences/tracked/BUILD.gn1
-rw-r--r--chromium/services/preferences/tracked/dictionary_hash_store_contents.cc7
-rw-r--r--chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc57
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.cc6
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.h2
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter_unittest.cc115
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_impl.cc4
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc38
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.cc47
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.h27
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc94
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.cc10
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.h2
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store_unittest.cc34
-rw-r--r--chromium/services/preferences/tracked/temp_scoped_dir_cleaner.h18
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc59
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h5
-rw-r--r--chromium/services/preferences/tracked/tracked_preferences_migration.cc4
-rw-r--r--chromium/services/preferences/unittest_helper_manifest.json14
-rw-r--r--chromium/services/preferences/unittest_manifest.json3
66 files changed, 3126 insertions, 1075 deletions
diff --git a/chromium/services/preferences/BUILD.gn b/chromium/services/preferences/BUILD.gn
index d60d44d0684..3e7a94d09a1 100644
--- a/chromium/services/preferences/BUILD.gn
+++ b/chromium/services/preferences/BUILD.gn
@@ -11,6 +11,11 @@ service_manifest("manifest") {
source = "manifest.json"
}
+service_manifest("local_state_manifest") {
+ name = "local_state"
+ source = "local_state_manifest.json"
+}
+
source_set("preferences") {
visibility = [
":*",
@@ -25,14 +30,16 @@ source_set("preferences") {
"//services/service_manager/public/cpp",
]
sources = [
- "persistent_pref_store_factory.cc",
- "persistent_pref_store_factory.h",
"persistent_pref_store_impl.cc",
"persistent_pref_store_impl.h",
+ "pref_store_impl.cc",
+ "pref_store_impl.h",
"pref_store_manager_impl.cc",
"pref_store_manager_impl.h",
"scoped_pref_connection_builder.cc",
"scoped_pref_connection_builder.h",
+ "shared_pref_registry.cc",
+ "shared_pref_registry.h",
]
}
@@ -55,6 +62,8 @@ source_set("tests") {
]
sources = [
"persistent_pref_store_impl_unittest.cc",
+ "pref_store_consistency_unittest.cc",
+ "pref_store_impl_unittest.cc",
]
if (!is_ios) {
sources += [ "pref_service_factory_unittest.cc" ]
@@ -65,7 +74,15 @@ source_set("tests") {
service_manifest("unittest_manifest") {
name = "prefs_unittests"
source = "unittest_manifest.json"
- packaged_services = [ ":manifest" ]
+ packaged_services = [
+ ":manifest",
+ ":unittest_helper_manifest",
+ ]
+}
+
+service_manifest("unittest_helper_manifest") {
+ name = "prefs_unittest_helper"
+ source = "unittest_helper_manifest.json"
}
catalog("tests_catalog") {
diff --git a/chromium/services/preferences/README.md b/chromium/services/preferences/README.md
new file mode 100644
index 00000000000..a74dd9315a1
--- /dev/null
+++ b/chromium/services/preferences/README.md
@@ -0,0 +1,82 @@
+# Preference Service User Guide
+
+[TOC]
+
+## What is the Preference Service?
+
+Preferences, also known as "prefs", are key-value pairs stored by
+Chrome. Examples include the settings in chrome://settings, all per-extension
+metadata, the list of plugins and so on. Individual prefs are keyed by a string
+and have a type. E.g., the "browser.enable_spellchecking" pref stores a boolean
+indicating whether spell-checking is enabled.
+
+The pref service persists prefs to disk and communicates updates to prefs
+between services, including Chrome itself. There is a pref service instance per
+profile (prefs are persisted on a per-profile basis).
+
+## Using the service
+
+The service is used through a client library that offers clients fast and
+synchronous access to prefs. To connect to the service and start reading and
+writing prefs simply use the `ConnectToPrefService` factory function:
+
+``` cpp
+#include "services/preferences/public/cpp/pref_service_factory.h"
+
+class MyService : public service_manager::Service {
+ void OnStart() {
+ auto* connector = context()->connector();
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ // Register any preferences you intend to use in |pref_registry|.
+ prefs::ConnectToPrefService(
+ connector, std::move(pref_registry), {},
+ base::Bind(&MyService::OnPrefServiceConnected, base::Unretained(this)));
+ }
+
+ void OnPrefServiceConnected(std::unique_ptr<::PrefService> pref_service) {
+ // Use |pref_service|.
+ }
+};
+```
+
+The returned `PrefService` class predates the Pref Service and its behavior
+hasn't changed (i.e. all existing documentation still applies).
+
+## Semantics
+
+Updates made on the `PrefService` object are reflected immediately in the
+originating service and eventually in all other services. In other words,
+updates are eventually consistent.
+
+## Registering your preferences
+
+Every pref should be owned by one service. The owning service provides the type
+and default value for that pref. Owned prefs can be registered as public,
+meaning other services can read and/or write them, or private (the default). Services
+that want to access a pref not owned by them must still register those prefs as
+"foreign" prefs. Registration happens through the `PrefRegistry` passed to
+`ConnectToPrefService`. For example:
+
+**`//services/my_service/my_service.cc`**
+``` cpp
+void MyService::OnStart() {
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterIntegerPref(kKey, kInitialValue, PrefRegistry::PUBLIC);
+ prefs::ConnectToPrefService(...);
+}
+```
+
+**`//services/other_service/other_service.cc`**
+``` cpp
+void OtherService::OnStart() {
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterForeignPref(kKey);
+ prefs::ConnectToPrefService(...);
+}
+```
+
+## Design
+
+The design doc is here:
+
+https://docs.google.com/document/d/1JU8QUWxMEXWMqgkvFUumKSxr7Z-nfq0YvreSJTkMVmU/edit?usp=sharing
diff --git a/chromium/services/preferences/local_state_manifest.json b/chromium/services/preferences/local_state_manifest.json
new file mode 100644
index 00000000000..f3c24684e71
--- /dev/null
+++ b/chromium/services/preferences/local_state_manifest.json
@@ -0,0 +1,15 @@
+{
+ "name": "local_state",
+ "display_name": "Local state preferences",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "pref_client": [
+ "prefs::mojom::PrefStoreConnector"
+ ]
+ },
+ "requires": {
+ }
+ }
+ }
+}
diff --git a/chromium/services/preferences/manifest.json b/chromium/services/preferences/manifest.json
index 40473465595..047409d2667 100644
--- a/chromium/services/preferences/manifest.json
+++ b/chromium/services/preferences/manifest.json
@@ -5,11 +5,7 @@
"service_manager:connector": {
"provides": {
"pref_client": [
- "prefs::mojom::PrefStoreConnector",
- "prefs::mojom::PrefStoreRegistry"
- ],
- "pref_control": [
- "prefs::mojom::PrefServiceControl"
+ "prefs::mojom::PrefStoreConnector"
]
},
"requires": {
diff --git a/chromium/services/preferences/persistent_pref_store_factory.cc b/chromium/services/preferences/persistent_pref_store_factory.cc
deleted file mode 100644
index 587ac96d182..00000000000
--- a/chromium/services/preferences/persistent_pref_store_factory.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/preferences/persistent_pref_store_factory.h"
-
-#include <memory>
-#include <utility>
-
-#include "components/prefs/json_pref_store.h"
-#include "components/prefs/pref_filter.h"
-#include "services/preferences/persistent_pref_store_impl.h"
-#include "services/preferences/tracked/tracked_persistent_pref_store_factory.h"
-
-namespace prefs {
-namespace {
-
-std::unique_ptr<PersistentPrefStoreImpl> CreateSimplePersistentPrefStore(
- mojom::SimplePersistentPrefStoreConfigurationPtr config,
- base::SequencedWorkerPool* worker_pool,
- base::Closure on_initialized) {
- return base::MakeUnique<PersistentPrefStoreImpl>(
- new JsonPrefStore(config->pref_filename,
- JsonPrefStore::GetTaskRunnerForFile(
- config->pref_filename.DirName(), worker_pool),
- nullptr),
- std::move(on_initialized));
-}
-
-} // namespace
-
-std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
- mojom::PersistentPrefStoreConfigurationPtr configuration,
- base::SequencedWorkerPool* worker_pool,
- base::Closure on_initialized) {
- if (configuration->is_simple_configuration()) {
- return CreateSimplePersistentPrefStore(
- std::move(configuration->get_simple_configuration()), worker_pool,
- std::move(on_initialized));
- }
- if (configuration->is_tracked_configuration()) {
- return base::MakeUnique<PersistentPrefStoreImpl>(
- CreateTrackedPersistentPrefStore(
- std::move(configuration->get_tracked_configuration()), worker_pool),
- std::move(on_initialized));
- }
- NOTREACHED();
- return nullptr;
-}
-
-} // namespace prefs
diff --git a/chromium/services/preferences/persistent_pref_store_factory.h b/chromium/services/preferences/persistent_pref_store_factory.h
deleted file mode 100644
index 06cf8f701b0..00000000000
--- a/chromium/services/preferences/persistent_pref_store_factory.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
-#define SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
-
-#include <memory>
-
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-
-namespace base {
-class SequencedWorkerPool;
-}
-
-namespace prefs {
-class PersistentPrefStoreImpl;
-
-// Create a new mojom::PersistentPrefStore impl that runs on |worker_pool|
-// configured by |configuration|.
-std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
- mojom::PersistentPrefStoreConfigurationPtr configuration,
- base::SequencedWorkerPool* worker_pool,
- base::Closure on_initialized);
-
-} // namespace prefs
-
-#endif // SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
diff --git a/chromium/services/preferences/persistent_pref_store_impl.cc b/chromium/services/preferences/persistent_pref_store_impl.cc
index f5b4ae14d65..09357e3cc6d 100644
--- a/chromium/services/preferences/persistent_pref_store_impl.cc
+++ b/chromium/services/preferences/persistent_pref_store_impl.cc
@@ -16,6 +16,65 @@
#include "services/preferences/public/cpp/lib/util.h"
namespace prefs {
+namespace {
+
+// Creates a PrefUpdateValuePtr representing |value| at |path|.
+mojom::PrefUpdateValuePtr CreatePrefUpdate(const std::vector<std::string>& path,
+ const base::Value* value) {
+ if (path.empty()) {
+ return mojom::PrefUpdateValue::NewAtomicUpdate(
+ value ? value->CreateDeepCopy() : nullptr);
+ }
+ std::vector<mojom::SubPrefUpdatePtr> pref_updates;
+ pref_updates.emplace_back(base::in_place, path,
+ value ? value->CreateDeepCopy() : nullptr);
+ return mojom::PrefUpdateValue::NewSplitUpdates(std::move(pref_updates));
+}
+
+// Returns a mojom::PrefUpdateValuePtr for |path| relative to |value|. If the
+// full path does not exist, a PrefUpdateValue containing the closest value is
+// returned.
+//
+// For example, for a |path| of {"foo", "bar"}:
+// - with a |value| of
+// {
+// "foo": 1
+// }
+// returns a path {"foo"} and value 1.
+//
+// - with a |value| of
+// {}
+// returns a path {"foo"} and null value.
+//
+// - with a |value| of
+// {
+// "foo": {}
+// }
+// returns a path {"foo", "bar"} and null value.
+//
+// - with a |value| of
+// {
+// "foo": {
+// "bar": "baz"
+// }
+// }
+// returns a path {"foo", "bar"} and value "baz".
+mojom::PrefUpdateValuePtr LookupPrefUpdate(const std::vector<std::string>& path,
+ const base::Value* value) {
+ if (!value)
+ return CreatePrefUpdate(std::vector<std::string>(), value);
+
+ for (size_t i = 0; i < path.size(); ++i) {
+ const base::DictionaryValue* dictionary_value = nullptr;
+ if (!value->GetAsDictionary(&dictionary_value) ||
+ !dictionary_value->Get(path[i], &value)) {
+ return CreatePrefUpdate({path.begin(), path.begin() + i}, value);
+ }
+ }
+ return CreatePrefUpdate(path, value);
+}
+
+} // namespace
class PersistentPrefStoreImpl::Connection : public mojom::PersistentPrefStore {
public:
@@ -55,9 +114,24 @@ class PersistentPrefStoreImpl::Connection : public mojom::PersistentPrefStore {
void SetValues(std::vector<mojom::PrefUpdatePtr> updates) override {
base::AutoReset<bool> scoped_call_in_progress(&write_in_progress_, true);
pref_store_->SetValues(std::move(updates));
+ observer_->OnPrefChangeAck();
+ }
+
+ void RequestValue(const std::string& key,
+ const std::vector<std::string>& path) override {
+ if (!base::ContainsKey(observed_keys_, key))
+ return;
+
+ const base::Value* value = nullptr;
+ pref_store_->GetValue(key, &value);
+ std::vector<mojom::PrefUpdatePtr> updates;
+ updates.emplace_back(base::in_place, key, LookupPrefUpdate(path, value), 0);
+ observer_->OnPrefsChanged(std::move(updates));
}
- void CommitPendingWrite() override { pref_store_->CommitPendingWrite(); }
+ void CommitPendingWrite(CommitPendingWriteCallback done_callback) override {
+ pref_store_->CommitPendingWrite(std::move(done_callback));
+ }
void SchedulePendingLossyWrites() override {
pref_store_->SchedulePendingLossyWrites();
}
@@ -83,15 +157,16 @@ PersistentPrefStoreImpl::PersistentPrefStoreImpl(
scoped_refptr<PersistentPrefStore> backing_pref_store,
base::OnceClosure on_initialized)
: backing_pref_store_(backing_pref_store) {
+ backing_pref_store_->AddObserver(this);
if (!backing_pref_store_->IsInitializationComplete()) {
- backing_pref_store_->AddObserver(this);
on_initialized_ = std::move(on_initialized);
initializing_ = true;
- backing_pref_store_->ReadPrefsAsync(nullptr);
}
}
-PersistentPrefStoreImpl::~PersistentPrefStoreImpl() = default;
+PersistentPrefStoreImpl::~PersistentPrefStoreImpl() {
+ backing_pref_store_->RemoveObserver(this);
+}
mojom::PersistentPrefStoreConnectionPtr
PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
@@ -106,6 +181,7 @@ PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
mojom::PrefStoreObserverPtr observer;
mojom::PrefStoreObserverRequest observer_request =
mojo::MakeRequest(&observer);
+ auto values = FilterPrefs(backing_pref_store_->GetValues(), observed_prefs);
auto connection = base::MakeUnique<Connection>(
this, mojo::MakeRequest(&pref_store_ptr), std::move(observer),
std::move(observed_prefs));
@@ -113,22 +189,38 @@ PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
connections_.insert(std::make_pair(connection_ptr, std::move(connection)));
return mojom::PersistentPrefStoreConnection::New(
mojom::PrefStoreConnection::New(std::move(observer_request),
- backing_pref_store_->GetValues(), true),
+ std::move(values), true),
std::move(pref_store_ptr), backing_pref_store_->GetReadError(),
backing_pref_store_->ReadOnly());
}
-void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {}
+void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {
+ if (write_in_progress_)
+ return;
+
+ const base::Value* value = nullptr;
+ for (auto& entry : connections_) {
+ auto update_value = mojom::PrefUpdateValue::New();
+ if (GetValue(key, &value)) {
+ update_value->set_atomic_update(value->CreateDeepCopy());
+ } else {
+ update_value->set_atomic_update(nullptr);
+ }
+ std::vector<mojom::PrefUpdatePtr> updates;
+ updates.emplace_back(base::in_place, key, std::move(update_value), 0);
+ entry.first->OnPrefValuesChanged(updates);
+ }
+}
void PersistentPrefStoreImpl::OnInitializationCompleted(bool succeeded) {
DCHECK(initializing_);
- backing_pref_store_->RemoveObserver(this);
initializing_ = false;
std::move(on_initialized_).Run();
}
void PersistentPrefStoreImpl::SetValues(
std::vector<mojom::PrefUpdatePtr> updates) {
+ base::AutoReset<bool> scoped_call_in_progress(&write_in_progress_, true);
for (auto& entry : connections_)
entry.first->OnPrefValuesChanged(updates);
@@ -171,8 +263,14 @@ void PersistentPrefStoreImpl::SetValues(
}
}
-void PersistentPrefStoreImpl::CommitPendingWrite() {
- backing_pref_store_->CommitPendingWrite();
+bool PersistentPrefStoreImpl::GetValue(const std::string& key,
+ const base::Value** value) const {
+ return backing_pref_store_->GetValue(key, value);
+}
+
+void PersistentPrefStoreImpl::CommitPendingWrite(
+ base::OnceClosure done_callback) {
+ backing_pref_store_->CommitPendingWrite(std::move(done_callback));
}
void PersistentPrefStoreImpl::SchedulePendingLossyWrites() {
diff --git a/chromium/services/preferences/persistent_pref_store_impl.h b/chromium/services/preferences/persistent_pref_store_impl.h
index 5111ed7f4e2..9d888936b05 100644
--- a/chromium/services/preferences/persistent_pref_store_impl.h
+++ b/chromium/services/preferences/persistent_pref_store_impl.h
@@ -6,10 +6,12 @@
#define SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_IMPL_H_
#include <memory>
+#include <set>
#include <string>
#include <unordered_map>
#include <vector>
+#include "base/callback.h"
#include "base/macros.h"
#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
@@ -37,8 +39,9 @@ class PersistentPrefStoreImpl : public PrefStore::Observer {
class Connection;
void SetValues(std::vector<mojom::PrefUpdatePtr> updates);
+ bool GetValue(const std::string& key, const base::Value** value) const;
- void CommitPendingWrite();
+ void CommitPendingWrite(base::OnceClosure done_callback);
void SchedulePendingLossyWrites();
void ClearMutableValues();
@@ -56,6 +59,10 @@ class PersistentPrefStoreImpl : public PrefStore::Observer {
base::OnceClosure on_initialized_;
+ // If true then a write is in progress and any update notifications should be
+ // ignored, as those updates would originate from ourselves.
+ bool write_in_progress_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImpl);
};
diff --git a/chromium/services/preferences/persistent_pref_store_impl_unittest.cc b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
index 7a326276c0a..ad364efb1bd 100644
--- a/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
+++ b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -32,7 +32,12 @@ class PrefStoreObserverMock : public PrefStore::Observer {
class PersistentPrefStoreMock : public InMemoryPrefStore {
public:
- MOCK_METHOD0(CommitPendingWrite, void());
+ void CommitPendingWrite(base::OnceClosure callback) override {
+ CommitPendingWriteMock();
+ InMemoryPrefStore::CommitPendingWrite(std::move(callback));
+ }
+
+ MOCK_METHOD0(CommitPendingWriteMock, void());
MOCK_METHOD0(SchedulePendingLossyWrites, void());
MOCK_METHOD0(ClearMutableValues, void());
@@ -50,56 +55,6 @@ void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
pref_store->RemoveObserver(&observer);
}
-class InitializationMockPersistentPrefStore : public InMemoryPrefStore {
- public:
- InitializationMockPersistentPrefStore(
- bool success,
- PersistentPrefStore::PrefReadError error,
- bool read_only)
- : success_(success), read_error_(error), read_only_(read_only) {}
-
- bool IsInitializationComplete() const override {
- return initialized_ && success_;
- }
-
- void AddObserver(PrefStore::Observer* observer) override {
- observers_.AddObserver(observer);
- }
-
- void RemoveObserver(PrefStore::Observer* observer) override {
- observers_.RemoveObserver(observer);
- }
-
- void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {
- DCHECK(!error_delegate);
- DCHECK(!initialized_);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&InitializationMockPersistentPrefStore::CompleteRead, this));
- }
-
- void CompleteRead() {
- initialized_ = true;
- for (auto& observer : observers_) {
- observer.OnInitializationCompleted(success_);
- }
- }
-
- PersistentPrefStore::PrefReadError GetReadError() const override {
- return read_error_;
- }
- bool ReadOnly() const override { return read_only_; }
-
- private:
- ~InitializationMockPersistentPrefStore() override = default;
-
- bool initialized_ = false;
- bool success_;
- PersistentPrefStore::PrefReadError read_error_;
- bool read_only_;
- base::ObserverList<PrefStore::Observer, true> observers_;
-};
-
constexpr char kKey[] = "path.to.key";
constexpr char kOtherKey[] = "path.to.other_key";
@@ -146,37 +101,27 @@ class PersistentPrefStoreImplTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImplTest);
};
-TEST_F(PersistentPrefStoreImplTest, InitializationSuccess) {
- auto backing_pref_store =
- make_scoped_refptr(new InitializationMockPersistentPrefStore(
- true, PersistentPrefStore::PREF_READ_ERROR_NONE, false));
- CreateImpl(backing_pref_store);
- EXPECT_TRUE(pref_store()->IsInitializationComplete());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
- pref_store()->GetReadError());
- EXPECT_FALSE(pref_store()->ReadOnly());
-}
-
-TEST_F(PersistentPrefStoreImplTest, InitializationFailure) {
- auto backing_pref_store =
- make_scoped_refptr(new InitializationMockPersistentPrefStore(
- false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true));
- CreateImpl(backing_pref_store);
- EXPECT_FALSE(pref_store()->IsInitializationComplete());
- EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
- pref_store()->GetReadError());
- EXPECT_TRUE(pref_store()->ReadOnly());
-}
-
TEST_F(PersistentPrefStoreImplTest, InitialValue) {
+ constexpr char kUnregisteredKey[] = "path.to.unregistered_key";
+ constexpr char kUnregisteredTopLevelKey[] = "unregistered_key";
+ constexpr char kUnregisteredPrefixKey[] = "p";
auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
const base::Value value("value");
backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ backing_pref_store->SetValue(kUnregisteredKey, value.CreateDeepCopy(), 0);
+ backing_pref_store->SetValue(kUnregisteredPrefixKey, value.CreateDeepCopy(),
+ 0);
+ backing_pref_store->SetValue(kUnregisteredTopLevelKey, value.CreateDeepCopy(),
+ 0);
CreateImpl(backing_pref_store);
EXPECT_TRUE(pref_store()->IsInitializationComplete());
const base::Value* output = nullptr;
ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
EXPECT_TRUE(value.Equals(output));
+
+ EXPECT_FALSE(pref_store()->GetValue(kUnregisteredKey, nullptr));
+ EXPECT_FALSE(pref_store()->GetValue(kUnregisteredTopLevelKey, nullptr));
+ EXPECT_FALSE(pref_store()->GetValue(kUnregisteredPrefixKey, nullptr));
}
TEST_F(PersistentPrefStoreImplTest, InitialValueWithoutPathExpansion) {
@@ -200,7 +145,7 @@ TEST_F(PersistentPrefStoreImplTest, WriteObservedByOtherClient) {
EXPECT_TRUE(other_pref_store->IsInitializationComplete());
const base::Value value("value");
- pref_store()->SetValueSilently(kKey, value.CreateDeepCopy(), 0);
+ pref_store()->SetValue(kKey, value.CreateDeepCopy(), 0);
ExpectPrefChange(other_pref_store.get(), kKey);
const base::Value* output = nullptr;
@@ -303,10 +248,8 @@ TEST_F(PersistentPrefStoreImplTest, CommitPendingWrite) {
auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
CreateImpl(backing_store);
base::RunLoop run_loop;
- EXPECT_CALL(*backing_store, CommitPendingWrite())
- .Times(2)
- .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
- pref_store()->CommitPendingWrite();
+ EXPECT_CALL(*backing_store, CommitPendingWriteMock()).Times(2);
+ pref_store()->CommitPendingWrite(run_loop.QuitClosure());
run_loop.Run();
}
@@ -316,7 +259,7 @@ TEST_F(PersistentPrefStoreImplTest, SchedulePendingLossyWrites) {
base::RunLoop run_loop;
EXPECT_CALL(*backing_store, SchedulePendingLossyWrites())
.WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
- EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ EXPECT_CALL(*backing_store, CommitPendingWriteMock()).Times(1);
pref_store()->SchedulePendingLossyWrites();
run_loop.Run();
}
@@ -327,7 +270,7 @@ TEST_F(PersistentPrefStoreImplTest, ClearMutableValues) {
base::RunLoop run_loop;
EXPECT_CALL(*backing_store, ClearMutableValues())
.WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
- EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ EXPECT_CALL(*backing_store, CommitPendingWriteMock()).Times(1);
pref_store()->ClearMutableValues();
run_loop.Run();
}
diff --git a/chromium/services/preferences/pref_service_factory_unittest.cc b/chromium/services/preferences/pref_service_factory_unittest.cc
index fad18de480b..9166e96a0d1 100644
--- a/chromium/services/preferences/pref_service_factory_unittest.cc
+++ b/chromium/services/preferences/pref_service_factory_unittest.cc
@@ -9,15 +9,17 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/sequenced_worker_pool_owner.h"
+#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_service_factory.h"
#include "components/prefs/value_map_pref_store.h"
#include "components/prefs/writeable_pref_store.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/pref_store_impl.h"
#include "services/preferences/public/cpp/dictionary_value_update.h"
#include "services/preferences/public/cpp/pref_service_main.h"
-#include "services/preferences/public/cpp/pref_store_impl.h"
#include "services/preferences/public/cpp/scoped_pref_update.h"
#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
@@ -31,10 +33,19 @@ namespace {
class ServiceTestClient : public service_manager::test::ServiceTestClient,
public service_manager::mojom::ServiceFactory {
public:
- ServiceTestClient(service_manager::test::ServiceTest* test,
- scoped_refptr<base::SequencedWorkerPool> worker_pool)
+ ServiceTestClient(
+ service_manager::test::ServiceTest* test,
+ scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store,
+ scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store,
+ scoped_refptr<PersistentPrefStore> user_prefs,
+ scoped_refptr<PrefRegistry> pref_registry,
+ base::OnceCallback<void(service_manager::Connector*)> connector_callback)
: service_manager::test::ServiceTestClient(test),
- worker_pool_(std::move(worker_pool)) {
+ above_user_prefs_pref_store_(std::move(above_user_prefs_pref_store)),
+ below_user_prefs_pref_store_(std::move(below_user_prefs_pref_store)),
+ user_prefs_(std::move(user_prefs)),
+ pref_registry_(std::move(pref_registry)),
+ connector_callback_(std::move(connector_callback)) {
registry_.AddInterface<service_manager::mojom::ServiceFactory>(
base::Bind(&ServiceTestClient::Create, base::Unretained(this)));
}
@@ -43,8 +54,7 @@ class ServiceTestClient : public service_manager::test::ServiceTestClient,
void OnBindInterface(const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override {
- registry_.BindInterface(source_info, interface_name,
- std::move(interface_pipe));
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void CreateService(service_manager::mojom::ServiceRequest request,
@@ -52,25 +62,35 @@ class ServiceTestClient : public service_manager::test::ServiceTestClient,
if (name == prefs::mojom::kServiceName) {
pref_service_context_.reset(new service_manager::ServiceContext(
CreatePrefService(
- {PrefValueStore::COMMAND_LINE_STORE,
- PrefValueStore::RECOMMENDED_STORE, PrefValueStore::USER_STORE,
- PrefValueStore::DEFAULT_STORE},
- worker_pool_),
+ nullptr, nullptr, nullptr, above_user_prefs_pref_store_.get(),
+ user_prefs_.get(), nullptr, below_user_prefs_pref_store_.get(),
+ pref_registry_.get())
+ .first,
std::move(request)));
+ } else if (name == "prefs_unittest_helper") {
+ test_helper_service_context_ =
+ base::MakeUnique<service_manager::ServiceContext>(
+ base::MakeUnique<service_manager::Service>(), std::move(request));
+ std::move(connector_callback_)
+ .Run(test_helper_service_context_->connector());
}
}
- void Create(const service_manager::BindSourceInfo& source_info,
- service_manager::mojom::ServiceFactoryRequest request) {
+ void Create(service_manager::mojom::ServiceFactoryRequest request) {
service_factory_bindings_.AddBinding(this, std::move(request));
}
private:
- scoped_refptr<base::SequencedWorkerPool> worker_pool_;
service_manager::BinderRegistry registry_;
mojo::BindingSet<service_manager::mojom::ServiceFactory>
service_factory_bindings_;
+ scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store_;
+ scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store_;
+ scoped_refptr<PersistentPrefStore> user_prefs_;
+ scoped_refptr<PrefRegistry> pref_registry_;
std::unique_ptr<service_manager::ServiceContext> pref_service_context_;
+ std::unique_ptr<service_manager::ServiceContext> test_helper_service_context_;
+ base::OnceCallback<void(service_manager::Connector*)> connector_callback_;
};
constexpr int kInitialValue = 1;
@@ -78,69 +98,107 @@ constexpr int kUpdatedValue = 2;
constexpr char kKey[] = "some_key";
constexpr char kOtherKey[] = "some_other_key";
constexpr char kDictionaryKey[] = "a.dictionary.pref";
+constexpr char kInitialKey[] = "initial_key";
+constexpr char kOtherInitialKey[] = "other_initial_key";
class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
public:
- PrefServiceFactoryTest()
- : ServiceTest("prefs_unittests", false),
- worker_pool_owner_(2, "PrefServiceFactoryTest") {}
+ PrefServiceFactoryTest() : ServiceTest("prefs_unittests", false) {}
protected:
void SetUp() override {
- ServiceTest::SetUp();
- ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
-
- // Init the pref service (in production Chrome startup would do this.)
- mojom::PrefServiceControlPtr control;
- connector()->BindInterface(mojom::kServiceName, &control);
- auto config = mojom::PersistentPrefStoreConfiguration::New();
- config->set_simple_configuration(
- mojom::SimplePersistentPrefStoreConfiguration::New(
- profile_dir_.GetPath().AppendASCII("Preferences")));
- control->Init(std::move(config));
above_user_prefs_pref_store_ = new ValueMapPrefStore();
below_user_prefs_pref_store_ = new ValueMapPrefStore();
- connector()->BindInterface(mojom::kServiceName, &pref_store_registry_);
- CreateLayeredPrefStores();
+ user_prefs_ = new InMemoryPrefStore();
+ PrefServiceFactory factory;
+ factory.set_user_prefs(user_prefs_);
+ factory.set_recommended_prefs(below_user_prefs_pref_store_);
+ factory.set_command_line_prefs(above_user_prefs_pref_store_);
+ pref_service_ = factory.Create(GetInitialPrefRegistry().get());
+
+ base::RunLoop run_loop;
+ connector_callback_ =
+ base::BindOnce(&PrefServiceFactoryTest::SetOtherClientConnector,
+ base::Unretained(this), run_loop.QuitClosure());
+ ServiceTest::SetUp();
+ ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
+ connector()->StartService("prefs_unittest_helper");
+ run_loop.Run();
}
- virtual void CreateLayeredPrefStores() {
- above_user_prefs_impl_ = PrefStoreImpl::Create(
- pref_store_registry(), above_user_prefs_pref_store_,
- PrefValueStore::COMMAND_LINE_STORE);
- below_user_prefs_impl_ = PrefStoreImpl::Create(
- pref_store_registry(), below_user_prefs_pref_store_,
- PrefValueStore::RECOMMENDED_STORE);
+ service_manager::Connector* other_client_connector() {
+ return other_client_connector_;
}
// service_manager::test::ServiceTest:
std::unique_ptr<service_manager::Service> CreateService() override {
- return base::MakeUnique<ServiceTestClient>(this, worker_pool_owner_.pool());
+ return base::MakeUnique<ServiceTestClient>(
+ this, above_user_prefs_pref_store_, below_user_prefs_pref_store_,
+ user_prefs_, GetInitialPrefRegistry().get(),
+ std::move(connector_callback_));
}
// Create a fully initialized PrefService synchronously.
std::unique_ptr<PrefService> Create() {
+ return CreateImpl(CreateDefaultPrefRegistry(), connector());
+ }
+
+ std::unique_ptr<PrefService> CreateForeign() {
+ return CreateImpl(CreateDefaultForeignPrefRegistry(),
+ other_client_connector());
+ }
+
+ std::unique_ptr<PrefService> CreateImpl(
+ scoped_refptr<PrefRegistry> pref_registry,
+ service_manager::Connector* connector) {
std::unique_ptr<PrefService> pref_service;
base::RunLoop run_loop;
- CreateAsync(std::vector<PrefValueStore::PrefStoreType>(),
- run_loop.QuitClosure(), &pref_service);
+ CreateAsync(std::move(pref_registry), connector, run_loop.QuitClosure(),
+ &pref_service);
run_loop.Run();
return pref_service;
}
- void CreateAsync(
- const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
- base::Closure callback,
- std::unique_ptr<PrefService>* out) {
- auto pref_registry = make_scoped_refptr(new PrefRegistrySimple());
- pref_registry->RegisterIntegerPref(kKey, kInitialValue);
- pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue);
- pref_registry->RegisterDictionaryPref(kDictionaryKey);
+ void CreateAsync(scoped_refptr<PrefRegistry> pref_registry,
+ service_manager::Connector* connector,
+ base::Closure callback,
+ std::unique_ptr<PrefService>* out) {
ConnectToPrefService(
- connector(), pref_registry, already_connected_types,
+ connector, std::move(pref_registry),
base::Bind(&PrefServiceFactoryTest::OnCreate, callback, out));
}
+ scoped_refptr<PrefRegistrySimple> GetInitialPrefRegistry() {
+ if (!pref_registry_) {
+ pref_registry_ = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry_->RegisterIntegerPref(kInitialKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ pref_registry_->RegisterIntegerPref(kOtherInitialKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ }
+ return pref_registry_;
+ }
+
+ scoped_refptr<PrefRegistrySimple> CreateDefaultPrefRegistry() {
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterIntegerPref(kKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ pref_registry->RegisterDictionaryPref(kDictionaryKey, PrefRegistry::PUBLIC);
+ pref_registry->RegisterForeignPref(kInitialKey);
+ pref_registry->RegisterForeignPref(kOtherInitialKey);
+ return pref_registry;
+ }
+
+ scoped_refptr<PrefRegistrySimple> CreateDefaultForeignPrefRegistry() {
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterForeignPref(kKey);
+ pref_registry->RegisterForeignPref(kOtherKey);
+ pref_registry->RegisterForeignPref(kDictionaryKey);
+ return pref_registry;
+ }
+
// Wait until first update of the pref |key| in |pref_service| synchronously.
void WaitForPrefChange(PrefService* pref_service, const std::string& key) {
PrefChangeRegistrar registrar;
@@ -156,14 +214,13 @@ class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
WriteablePrefStore* below_user_prefs_pref_store() {
return below_user_prefs_pref_store_.get();
}
- mojom::PrefStoreRegistry* pref_store_registry() {
- return pref_store_registry_.get();
- }
+ PrefService* pref_service() { return pref_service_.get(); }
private:
- // Called when the PrefService has been initialized.
- static void OnInit(const base::Closure& quit_closure, bool success) {
- quit_closure.Run();
+ void SetOtherClientConnector(base::OnceClosure done,
+ service_manager::Connector* connector) {
+ other_client_connector_ = connector;
+ std::move(done).Run();
}
// Called when the PrefService has been created.
@@ -172,12 +229,6 @@ class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
std::unique_ptr<PrefService> pref_service) {
DCHECK(pref_service);
*out = std::move(pref_service);
- if ((*out)->GetInitializationStatus() ==
- PrefService::INITIALIZATION_STATUS_WAITING) {
- (*out)->AddPrefInitObserver(
- base::Bind(PrefServiceFactoryTest::OnInit, quit_closure));
- return;
- }
quit_closure.Run();
}
@@ -189,12 +240,13 @@ class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
}
base::ScopedTempDir profile_dir_;
- base::SequencedWorkerPoolOwner worker_pool_owner_;
scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store_;
- std::unique_ptr<PrefStoreImpl> above_user_prefs_impl_;
scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store_;
- std::unique_ptr<PrefStoreImpl> below_user_prefs_impl_;
- mojom::PrefStoreRegistryPtr pref_store_registry_;
+ scoped_refptr<PersistentPrefStore> user_prefs_;
+ scoped_refptr<PrefRegistrySimple> pref_registry_;
+ std::unique_ptr<PrefService> pref_service_;
+ service_manager::Connector* other_client_connector_ = nullptr;
+ base::OnceCallback<void(service_manager::Connector*)> connector_callback_;
DISALLOW_COPY_AND_ASSIGN(PrefServiceFactoryTest);
};
@@ -211,7 +263,7 @@ TEST_F(PrefServiceFactoryTest, Basic) {
// Check that updates in one client eventually propagates to the other.
TEST_F(PrefServiceFactoryTest, MultipleClients) {
auto pref_service = Create();
- auto pref_service2 = Create();
+ auto pref_service2 = CreateForeign();
EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kKey));
@@ -220,6 +272,59 @@ TEST_F(PrefServiceFactoryTest, MultipleClients) {
EXPECT_EQ(kUpdatedValue, pref_service2->GetInteger(kKey));
}
+// Check that updates in one client eventually propagates to the other.
+TEST_F(PrefServiceFactoryTest, InternalAndExternalClients) {
+ auto pref_service2 = Create();
+
+ EXPECT_EQ(kInitialValue, pref_service()->GetInteger(kInitialKey));
+ EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kInitialKey));
+ EXPECT_EQ(kInitialValue, pref_service()->GetInteger(kOtherInitialKey));
+ EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kOtherInitialKey));
+ pref_service()->SetInteger(kInitialKey, kUpdatedValue);
+ WaitForPrefChange(pref_service2.get(), kInitialKey);
+ EXPECT_EQ(kUpdatedValue, pref_service2->GetInteger(kInitialKey));
+
+ pref_service2->SetInteger(kOtherInitialKey, kUpdatedValue);
+ WaitForPrefChange(pref_service(), kOtherInitialKey);
+ EXPECT_EQ(kUpdatedValue, pref_service()->GetInteger(kOtherInitialKey));
+}
+
+TEST_F(PrefServiceFactoryTest, MultipleConnectionsFromSingleClient) {
+ Create();
+ CreateForeign();
+ Create();
+ CreateForeign();
+}
+
+// Check that defaults set by one client are correctly shared to the other
+// client.
+TEST_F(PrefServiceFactoryTest, MultipleClients_Defaults) {
+ std::unique_ptr<PrefService> pref_service, pref_service2;
+ {
+ base::RunLoop run_loop;
+ auto done_closure = base::BarrierClosure(2, run_loop.QuitClosure());
+
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterIntegerPref(kKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ pref_registry->RegisterForeignPref(kOtherKey);
+ auto pref_registry2 = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry2->RegisterForeignPref(kKey);
+ pref_registry2->RegisterIntegerPref(kOtherKey, kInitialValue,
+ PrefRegistry::PUBLIC);
+ CreateAsync(std::move(pref_registry), connector(), done_closure,
+ &pref_service);
+ CreateAsync(std::move(pref_registry2), other_client_connector(),
+ done_closure, &pref_service2);
+ run_loop.Run();
+ }
+
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+ EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kKey));
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kOtherKey));
+ EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kOtherKey));
+}
+
// Check that read-only pref store changes are observed.
TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore) {
auto pref_service = Create();
@@ -278,7 +383,7 @@ void Fail(PrefService* pref_service) {
TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Basic) {
auto pref_service = Create();
- auto pref_service2 = Create();
+ auto pref_service2 = CreateForeign();
void (*updates[])(ScopedDictionaryPrefUpdate*) = {
[](ScopedDictionaryPrefUpdate* update) {
@@ -436,7 +541,7 @@ TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Basic) {
TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Erase) {
auto pref_service = Create();
- auto pref_service2 = Create();
+ auto pref_service2 = CreateForeign();
{
ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey);
update->SetInteger("path.to.integer", 1);
@@ -454,7 +559,7 @@ TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_Erase) {
TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_ClearDictionary) {
auto pref_service = Create();
- auto pref_service2 = Create();
+ auto pref_service2 = CreateForeign();
{
ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey);
@@ -474,11 +579,16 @@ TEST_F(PrefServiceFactoryTest, MultipleClients_SubPrefUpdates_ClearDictionary) {
TEST_F(PrefServiceFactoryTest,
MultipleClients_SubPrefUpdates_ClearEmptyDictionary) {
auto pref_service = Create();
- auto pref_service2 = Create();
+ auto pref_service2 = CreateForeign();
{
ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey);
- update.Get();
+ update->SetInteger(kKey, kInitialValue);
+ }
+ WaitForPrefChange(pref_service2.get(), kDictionaryKey);
+ {
+ ScopedDictionaryPrefUpdate update(pref_service.get(), kDictionaryKey);
+ update->Remove(kKey, nullptr);
}
WaitForPrefChange(pref_service2.get(), kDictionaryKey);
EXPECT_TRUE(pref_service2->GetDictionary(kDictionaryKey)->empty());
@@ -494,89 +604,5 @@ TEST_F(PrefServiceFactoryTest,
WaitForPrefChange(pref_service2.get(), kKey);
}
-class PrefServiceFactoryManualPrefStoreRegistrationTest
- : public PrefServiceFactoryTest {
- protected:
- void CreateLayeredPrefStores() override {}
-};
-
-class ConnectionReportingPrefStoreImpl : public mojom::PrefStore {
- public:
- ConnectionReportingPrefStoreImpl(base::OnceClosure on_add_observer,
- mojom::PrefStoreRequest request)
- : on_add_observer_(std::move(on_add_observer)),
- binding_(this, std::move(request)) {}
-
- void AddObserver(const std::vector<std::string>& prefs_to_observe,
- AddObserverCallback callback) override {
- observer_added_ = true;
- if (on_add_observer_)
- std::move(on_add_observer_).Run();
-
- mojom::PrefStoreObserverPtr observer;
- auto values = base::MakeUnique<base::DictionaryValue>();
- values->Set(kKey, base::MakeUnique<base::Value>(kUpdatedValue));
- std::move(callback).Run(mojom::PrefStoreConnection::New(
- mojo::MakeRequest(&observer), std::move(values), true));
- }
-
- bool observer_added() { return observer_added_; }
-
- private:
- bool observer_added_ = false;
- base::OnceClosure on_add_observer_;
- mojo::Binding<mojom::PrefStore> binding_;
-};
-
-// Check that connect calls received before all read-only prefs stores have
-// been registered are correctly handled.
-TEST_F(PrefServiceFactoryManualPrefStoreRegistrationTest,
- RegistrationBeforeAndAfterConnect) {
- base::RunLoop add_observer_run_loop;
-
- mojom::PrefStorePtr below_ptr;
- ConnectionReportingPrefStoreImpl below_user_prefs(
- add_observer_run_loop.QuitClosure(), mojo::MakeRequest(&below_ptr));
- pref_store_registry()->Register(PrefValueStore::RECOMMENDED_STORE,
- std::move(below_ptr));
-
- std::unique_ptr<PrefService> pref_service;
- base::RunLoop run_loop;
- auto barrier = base::BarrierClosure(2, run_loop.QuitClosure());
- CreateAsync(std::vector<PrefValueStore::PrefStoreType>(), barrier,
- &pref_service);
-
- add_observer_run_loop.Run();
- ASSERT_TRUE(below_user_prefs.observer_added());
-
- EXPECT_FALSE(pref_service);
-
- mojom::PrefStorePtr above_ptr;
- ConnectionReportingPrefStoreImpl above_user_prefs(
- barrier, mojo::MakeRequest(&above_ptr));
- pref_store_registry()->Register(PrefValueStore::COMMAND_LINE_STORE,
- std::move(above_ptr));
-
- run_loop.Run();
- EXPECT_TRUE(above_user_prefs.observer_added());
- EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
- pref_service->SetInteger(kKey, kInitialValue);
- EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
-}
-
-// Check that connect calls claiming to have all read-only pref stores locally
-// do not wait for those stores to be registered with the pref service.
-TEST_F(PrefServiceFactoryManualPrefStoreRegistrationTest,
- LocalButNotRegisteredReadOnlyStores) {
- std::unique_ptr<PrefService> pref_service;
- base::RunLoop run_loop;
- CreateAsync(
- {PrefValueStore::RECOMMENDED_STORE, PrefValueStore::COMMAND_LINE_STORE},
- run_loop.QuitClosure(), &pref_service);
-
- run_loop.Run();
- EXPECT_TRUE(pref_service);
-}
-
} // namespace
} // namespace prefs
diff --git a/chromium/services/preferences/pref_store_consistency_unittest.cc b/chromium/services/preferences/pref_store_consistency_unittest.cc
new file mode 100644
index 00000000000..ade786d80c3
--- /dev/null
+++ b/chromium/services/preferences/pref_store_consistency_unittest.cc
@@ -0,0 +1,916 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/prefs/in_memory_pref_store.h"
+#include "components/prefs/pref_notifier_impl.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/public/cpp/dictionary_value_update.h"
+#include "services/preferences/public/cpp/persistent_pref_store_client.h"
+#include "services/preferences/public/cpp/scoped_pref_update.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace prefs {
+namespace {
+
+constexpr int kInitialValue = 1;
+constexpr char kKey[] = "key";
+constexpr char kNestedKey[] = "key.child";
+constexpr char kChildKey[] = "child";
+constexpr char kOtherKey[] = "other_key";
+constexpr char kNestedOtherKey[] = "key.other_key";
+constexpr char kDictionaryKey[] = "a.dictionary.pref";
+
+void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+struct UpdateOrAck {
+ std::vector<mojom::PrefUpdatePtr> updates;
+ bool is_ack;
+};
+
+struct Request {
+ std::string key;
+ std::vector<std::string> path;
+};
+
+struct UpdateOrRequest {
+ std::vector<mojom::PrefUpdatePtr> updates;
+ Request request;
+};
+
+// A client connection to a between a PersistentPrefStoreImpl and a
+// PersistentPrefStoreClient that provides control over when messages between
+// the two are delivered.
+class PrefServiceConnection : public mojom::PrefStoreObserver,
+ public mojom::PersistentPrefStore {
+ public:
+ explicit PrefServiceConnection(PersistentPrefStoreImpl* pref_store)
+ : observer_binding_(this), pref_store_binding_(this) {
+ auto connection = pref_store->CreateConnection({
+ kKey, kOtherKey, kDictionaryKey,
+ });
+ observer_binding_.Bind(
+ std::move(connection->pref_store_connection->observer));
+ connection->pref_store_connection->observer = mojo::MakeRequest(&observer_);
+
+ pref_store_ = std::move(connection->pref_store);
+ pref_store_binding_.Bind(mojo::MakeRequest(&connection->pref_store));
+
+ pref_store_client_ =
+ base::MakeRefCounted<PersistentPrefStoreClient>(std::move(connection));
+ PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
+ auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
+ pref_registry->RegisterIntegerPref(kKey, kInitialValue);
+ pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue);
+ pref_registry->RegisterDictionaryPref(kDictionaryKey);
+ auto* pref_value_store = new PrefValueStore(
+ nullptr, nullptr, nullptr, nullptr, pref_store_client_.get(), nullptr,
+ pref_registry->defaults().get(), pref_notifier);
+ pref_service_ = base::MakeUnique<::PrefService>(
+ pref_notifier, pref_value_store, pref_store_client_.get(),
+ pref_registry.get(), base::Bind(&DoNothingHandleReadError), true);
+ }
+
+ ~PrefServiceConnection() override {
+ observer_binding_.FlushForTesting();
+ pref_store_binding_.FlushForTesting();
+ EXPECT_TRUE(writes_.empty());
+ EXPECT_TRUE(updates_.empty());
+ }
+
+ PrefService& pref_service() { return *pref_service_; }
+
+ void WaitForWrites(size_t num_writes) {
+ if (writes_.size() >= num_writes)
+ return;
+
+ expected_writes_ = num_writes;
+ base::RunLoop run_loop;
+ stop_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+ void ForwardWrites(size_t num_writes) {
+ WaitForWrites(num_writes);
+ for (size_t i = 0; i < num_writes; ++i) {
+ auto& write = writes_.front();
+ if (write.updates.empty()) {
+ pref_store_->RequestValue(write.request.key, write.request.path);
+ } else {
+ pref_store_->SetValues(std::move(write.updates));
+ }
+ writes_.pop_front();
+ }
+ pref_store_.FlushForTesting();
+ }
+ void WaitForUpdates(size_t num_updates) {
+ if (updates_.size() >= num_updates)
+ return;
+
+ expected_updates_ = num_updates;
+ base::RunLoop run_loop;
+ stop_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ void ForwardUpdates(size_t num_updates) {
+ WaitForUpdates(num_updates);
+ for (size_t i = 0; i < num_updates; ++i) {
+ auto& update = updates_.front();
+ if (update.is_ack) {
+ observer_->OnPrefChangeAck();
+ } else {
+ observer_->OnPrefsChanged(std::move(update.updates));
+ }
+ updates_.pop_front();
+ }
+ observer_.FlushForTesting();
+ }
+
+ // mojom::PersistentPrefStore
+ void SetValues(std::vector<mojom::PrefUpdatePtr> updates) override {
+ writes_.push_back({std::move(updates)});
+ if (writes_.size() == expected_writes_) {
+ expected_writes_ = 0;
+ std::move(stop_).Run();
+ }
+ }
+ void RequestValue(const std::string& key,
+ const std::vector<std::string>& path) override {
+ writes_.push_back({std::vector<mojom::PrefUpdatePtr>(), {key, path}});
+ if (writes_.size() == expected_writes_) {
+ expected_writes_ = 0;
+ std::move(stop_).Run();
+ }
+ }
+ void CommitPendingWrite(base::OnceClosure) override {}
+ void SchedulePendingLossyWrites() override {}
+ void ClearMutableValues() override {}
+
+ // mojom::PrefStoreObserver
+ void OnPrefsChanged(std::vector<mojom::PrefUpdatePtr> updates) override {
+ updates_.push_back({std::move(updates), false});
+ if (updates_.size() == expected_updates_) {
+ expected_updates_ = 0;
+ std::move(stop_).Run();
+ }
+ }
+ void OnInitializationCompleted(bool succeeded) override { NOTREACHED(); }
+ void OnPrefChangeAck() override {
+ updates_.push_back({std::vector<mojom::PrefUpdatePtr>(), true});
+ acks_.push_back(updates_.size());
+ }
+
+ private:
+ scoped_refptr<PersistentPrefStoreClient> pref_store_client_;
+ std::unique_ptr<PrefService> pref_service_;
+ mojom::PrefStoreObserverPtr observer_;
+ mojom::PersistentPrefStorePtr pref_store_;
+ mojo::Binding<mojom::PrefStoreObserver> observer_binding_;
+ mojo::Binding<mojom::PersistentPrefStore> pref_store_binding_;
+
+ base::OnceClosure stop_;
+ size_t expected_writes_ = 0;
+ size_t expected_updates_ = 0;
+
+ std::deque<UpdateOrRequest> writes_;
+ std::deque<UpdateOrAck> updates_;
+ std::deque<size_t> acks_;
+};
+
+class PersistentPrefStoreConsistencyTest : public testing::Test {
+ public:
+ void SetUp() override {
+ pref_store_ = base::MakeRefCounted<InMemoryPrefStore>();
+ pref_store_impl_ = base::MakeUnique<PersistentPrefStoreImpl>(
+ pref_store_, base::BindOnce(&base::DoNothing));
+ }
+
+ PersistentPrefStore* pref_store() { return pref_store_.get(); }
+
+ std::unique_ptr<PrefServiceConnection> CreateConnection() {
+ return base::MakeUnique<PrefServiceConnection>(pref_store_impl_.get());
+ }
+
+ private:
+ scoped_refptr<PersistentPrefStore> pref_store_;
+ std::unique_ptr<PersistentPrefStoreImpl> pref_store_impl_;
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(PersistentPrefStoreConsistencyTest, TwoPrefs) {
+ pref_store()->SetValue(kKey, base::MakeUnique<base::Value>(kInitialValue), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+
+ EXPECT_EQ(kInitialValue, pref_service.GetInteger(kKey));
+ EXPECT_EQ(kInitialValue, pref_service2.GetInteger(kKey));
+
+ pref_service.SetInteger(kKey, 2);
+ pref_service2.SetInteger(kKey, 3);
+
+ // The writes arrive in the order: 2, 3.
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(2, pref_service.GetInteger(kKey));
+
+ // This connection already has a later value. It should not move backwards in
+ // time.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(3, pref_service2.GetInteger(kKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(3, pref_service.GetInteger(kKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(3, pref_service2.GetInteger(kKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, TwoSubPrefs) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 2);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ // The writes arrive in the order: 2, 3.
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue two_dict;
+ two_dict.SetInteger(kKey, 2);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(two_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ // This connection already has a later value. It should not move backwards in
+ // time.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, DifferentSubPrefs) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 2);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kOtherKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue two_dict;
+ two_dict.SetInteger(kKey, 2);
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 2);
+ expected_dict.SetInteger(kOtherKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(two_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ // This connection already has a later value. It should not move backwards in
+ // time.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, WriteParentThenChild) {
+ auto initial_value = base::MakeUnique<base::DictionaryValue>();
+ initial_value->SetDictionary(kDictionaryKey,
+ base::MakeUnique<base::DictionaryValue>());
+ pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 4);
+ update->Clear();
+ update->SetInteger(kKey, 2);
+ update->SetInteger(kOtherKey, 4);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue two_and_four_dict;
+ two_and_four_dict.SetInteger(kKey, 2);
+ two_and_four_dict.SetInteger(kOtherKey, 4);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kKey, 3);
+ three_dict.SetDictionary(kDictionaryKey,
+ base::MakeUnique<base::DictionaryValue>());
+ base::DictionaryValue five_dict = three_dict;
+ five_dict.SetInteger(kKey, 5);
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 3);
+ expected_dict.SetInteger(kOtherKey, 4);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(two_and_four_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ // Applying the other client's write would lose this client's write so is
+ // ignored. Instead, this client requests an updated value from the service.
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+ connection2->ForwardWrites(1);
+
+ // Perform another update while waiting for the updated value from the
+ // service.
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 5);
+ }
+ connection2->ForwardWrites(1);
+
+ expected_dict.SetInteger(kKey, 5);
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ // Ack for the original write.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(five_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ // New value that is ignored due to the second in-flight write.
+ connection2->ForwardUpdates(1);
+ // Sending another request for the value from the service.
+ connection2->ForwardWrites(1);
+ EXPECT_EQ(five_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ // Ack for the second write.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(five_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, WriteChildThenParent) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 4);
+ update->Clear();
+ update->SetInteger(kKey, 2);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ connection2->ForwardWrites(1);
+ connection->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 2);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, WriteChildThenDeleteParent) {
+ pref_store()->SetValue(kDictionaryKey,
+ base::MakeUnique<base::DictionaryValue>(), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ pref_service.ClearPref(kDictionaryKey);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ connection2->ForwardWrites(1);
+ connection->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 2);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service2.HasPrefPath(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, DeleteParentThenWriteChild) {
+ auto initial_value = base::MakeUnique<base::DictionaryValue>();
+ initial_value->SetInteger(kOtherKey, 5);
+ pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ pref_service.ClearPref(kDictionaryKey);
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue intermediate_dict;
+ intermediate_dict.SetInteger(kKey, 3);
+ intermediate_dict.SetInteger(kOtherKey, 5);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardWrites(1);
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, WriteParentThenDeleteChild) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 1);
+ update->Clear();
+ update->SetInteger(kKey, 2);
+ update->SetInteger(kOtherKey, 4);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ update->RemovePath(kKey, nullptr);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue two_and_four_dict;
+ two_and_four_dict.SetInteger(kKey, 2);
+ two_and_four_dict.SetInteger(kOtherKey, 4);
+ base::DictionaryValue empty_dict;
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kOtherKey, 4);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(two_and_four_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ // Applying the other client's write would lose this client's write so is
+ // ignored. Instead, this client requests an updated value from the service.
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+ connection2->ForwardWrites(1);
+
+ // Ack for the original write.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, DeleteChildThenWriteParent) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 4);
+ update->Clear();
+ update->SetInteger(kKey, 2);
+ update->SetInteger(kOtherKey, 4);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ update->RemovePath(kKey, nullptr);
+ }
+
+ connection2->ForwardWrites(1);
+ connection->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue empty_dict;
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 2);
+ expected_dict.SetInteger(kOtherKey, 4);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, ReplaceParentThenWriteChild) {
+ auto initial_value = base::MakeUnique<base::DictionaryValue>();
+ initial_value->SetInteger(kNestedOtherKey, 5);
+ pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 1);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kNestedKey, 2);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue simple_dict;
+ simple_dict.SetInteger(kKey, 1);
+ base::DictionaryValue nested_dict;
+ nested_dict.SetInteger(kNestedKey, 2);
+ nested_dict.SetInteger(kNestedOtherKey, 5);
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kNestedKey, 2);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(simple_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(nested_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardWrites(1);
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(nested_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, WriteChildThenReplaceParent) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->SetInteger(kKey, 1);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kNestedKey, 2);
+ }
+
+ connection2->ForwardWrites(1);
+ connection->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue simple_dict;
+ simple_dict.SetInteger(kKey, 1);
+ base::DictionaryValue nested_dict;
+ nested_dict.SetInteger(kNestedKey, 2);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(simple_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(simple_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(nested_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(simple_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, NestedWriteParentThenChild) {
+ pref_store()->SetValue(kKey, base::MakeUnique<base::DictionaryValue>(), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ auto nested_dict =
+ update->SetDictionary(kKey, base::MakeUnique<base::DictionaryValue>());
+ nested_dict->SetInteger(kChildKey, 2);
+ nested_dict->SetInteger(kOtherKey, 4);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kNestedKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue two_and_four_dict;
+ two_and_four_dict.SetInteger(kNestedKey, 2);
+ two_and_four_dict.SetInteger(kNestedOtherKey, 4);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kNestedKey, 3);
+ base::DictionaryValue expected_dict = two_and_four_dict;
+ expected_dict.SetInteger(kNestedKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(two_and_four_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ // Applying the other client's write would lose this client's write so is
+ // ignored. Instead, this client requests an updated value from the service.
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+ connection2->ForwardWrites(1);
+
+ // Ack for the original write.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ // Updated value from the service.
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest, NestedWriteChildThenParent) {
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ auto nested_dict =
+ update->SetDictionary(kKey, base::MakeUnique<base::DictionaryValue>());
+ nested_dict->SetInteger(kChildKey, 2);
+ nested_dict->SetInteger(kOtherKey, 4);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kNestedKey, 3);
+ }
+
+ connection2->ForwardWrites(1);
+ connection->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kNestedKey, 2);
+ expected_dict.SetInteger(kNestedOtherKey, 4);
+ base::DictionaryValue three_dict;
+ three_dict.SetInteger(kNestedKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(three_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest,
+ DeleteParentThenWriteChildThenDeleteParent) {
+ auto initial_value = base::MakeUnique<base::DictionaryValue>();
+ initial_value->SetInteger(kOtherKey, 5);
+ pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ pref_service.ClearPref(kDictionaryKey);
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue intermediate_dict;
+ intermediate_dict.SetInteger(kKey, 3);
+ intermediate_dict.SetInteger(kOtherKey, 5);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kKey, 3);
+
+ connection->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ pref_service.ClearPref(kDictionaryKey);
+ connection->ForwardWrites(1);
+ connection->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service.HasPrefPath(kDictionaryKey));
+
+ connection2->ForwardWrites(1);
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service2.HasPrefPath(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_FALSE(pref_service2.HasPrefPath(kDictionaryKey));
+}
+
+TEST_F(PersistentPrefStoreConsistencyTest,
+ NestedDeleteParentThenWriteChildThenDeleteChild) {
+ auto initial_value = base::MakeUnique<base::DictionaryValue>();
+ initial_value->SetInteger(kNestedOtherKey, 5);
+ pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
+ auto connection = CreateConnection();
+ auto connection2 = CreateConnection();
+ auto& pref_service = connection->pref_service();
+ auto& pref_service2 = connection2->pref_service();
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->RemovePath(kKey, nullptr);
+ }
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
+ update->SetInteger(kNestedKey, 3);
+ }
+
+ connection->ForwardWrites(1);
+ connection2->ForwardWrites(1);
+
+ connection->WaitForUpdates(2);
+ connection2->WaitForUpdates(2);
+
+ base::DictionaryValue intermediate_dict;
+ intermediate_dict.SetInteger(kNestedKey, 3);
+ intermediate_dict.SetInteger(kNestedOtherKey, 5);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.SetInteger(kNestedKey, 3);
+
+ base::DictionaryValue empty_dict;
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection->ForwardUpdates(1);
+ EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ {
+ ScopedDictionaryPrefUpdate update(&pref_service, kDictionaryKey);
+ update->RemovePath(kKey, nullptr);
+ }
+ connection->ForwardWrites(1);
+ connection->ForwardUpdates(1);
+ EXPECT_TRUE(pref_service.HasPrefPath(kDictionaryKey));
+ EXPECT_EQ(empty_dict, *pref_service.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardWrites(1);
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(intermediate_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+
+ connection2->ForwardUpdates(1);
+ EXPECT_EQ(empty_dict, *pref_service2.GetDictionary(kDictionaryKey));
+}
+
+} // namespace
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_impl.cc b/chromium/services/preferences/pref_store_impl.cc
index efcf8f3f6ed..de0575db8ea 100644
--- a/chromium/services/preferences/public/cpp/pref_store_impl.cc
+++ b/chromium/services/preferences/pref_store_impl.cc
@@ -2,21 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
#include <memory>
-#include <unordered_set>
+#include <set>
#include <utility>
#include "base/stl_util.h"
#include "base/values.h"
+#include "services/preferences/public/cpp/lib/util.h"
namespace prefs {
class PrefStoreImpl::Observer {
public:
- Observer(mojom::PrefStoreObserverPtr observer,
- std::unordered_set<std::string> prefs)
+ Observer(mojom::PrefStoreObserverPtr observer, std::set<std::string> prefs)
: observer_(std::move(observer)), prefs_(std::move(prefs)) {}
void OnInitializationCompleted(bool succeeded) {
@@ -46,16 +46,14 @@ class PrefStoreImpl::Observer {
private:
mojom::PrefStoreObserverPtr observer_;
- const std::unordered_set<std::string> prefs_;
+ const std::set<std::string> prefs_;
DISALLOW_COPY_AND_ASSIGN(Observer);
};
-PrefStoreImpl::PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
- mojom::PrefStoreRequest request)
+PrefStoreImpl::PrefStoreImpl(scoped_refptr<::PrefStore> pref_store)
: backing_pref_store_(std::move(pref_store)),
- backing_pref_store_initialized_(false),
- binding_(this, std::move(request)) {
+ backing_pref_store_initialized_(false) {
DCHECK(backing_pref_store_);
if (backing_pref_store_->IsInitializationComplete())
OnInitializationCompleted(true);
@@ -66,18 +64,6 @@ PrefStoreImpl::~PrefStoreImpl() {
backing_pref_store_->RemoveObserver(this);
}
-// static
-std::unique_ptr<PrefStoreImpl> PrefStoreImpl::Create(
- mojom::PrefStoreRegistry* registry_ptr,
- scoped_refptr<::PrefStore> pref_store,
- PrefValueStore::PrefStoreType type) {
- mojom::PrefStorePtr ptr;
- auto impl = base::MakeUnique<PrefStoreImpl>(std::move(pref_store),
- mojo::MakeRequest(&ptr));
- registry_ptr->Register(type, std::move(ptr));
- return impl;
-}
-
void PrefStoreImpl::OnPrefValueChanged(const std::string& key) {
auto dictionary = base::MakeUnique<base::DictionaryValue>();
const base::Value* value = nullptr;
@@ -100,18 +86,19 @@ void PrefStoreImpl::OnInitializationCompleted(bool succeeded) {
observer->OnInitializationCompleted(succeeded);
}
-void PrefStoreImpl::AddObserver(
- const std::vector<std::string>& prefs_to_observe,
- AddObserverCallback callback) {
+mojom::PrefStoreConnectionPtr PrefStoreImpl::AddObserver(
+ const std::vector<std::string>& prefs_to_observe) {
mojom::PrefStoreObserverPtr observer_ptr;
auto request = mojo::MakeRequest(&observer_ptr);
- observers_.push_back(base::MakeUnique<Observer>(
- std::move(observer_ptr),
- std::unordered_set<std::string>(prefs_to_observe.begin(),
- prefs_to_observe.end())));
- std::move(callback).Run(mojom::PrefStoreConnection::New(
- std::move(request), backing_pref_store_->GetValues(),
- backing_pref_store_->IsInitializationComplete()));
+ std::set<std::string> observed_prefs(prefs_to_observe.begin(),
+ prefs_to_observe.end());
+ auto result = mojom::PrefStoreConnection::New(
+ std::move(request),
+ FilterPrefs(backing_pref_store_->GetValues(), observed_prefs),
+ backing_pref_store_->IsInitializationComplete());
+ observers_.push_back(base::MakeUnique<Observer>(std::move(observer_ptr),
+ std::move(observed_prefs)));
+ return result;
}
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_impl.h b/chromium/services/preferences/pref_store_impl.h
index 6846611c6eb..8cb970247e7 100644
--- a/chromium/services/preferences/public/cpp/pref_store_impl.h
+++ b/chromium/services/preferences/pref_store_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
-#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+#ifndef SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
+#define SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
#include <string>
#include <vector>
@@ -19,18 +19,13 @@ namespace prefs {
// Wraps an actual PrefStore implementation and exposes it as a
// mojom::PrefStore interface.
-class PrefStoreImpl : public ::PrefStore::Observer, public mojom::PrefStore {
+class PrefStoreImpl : public ::PrefStore::Observer {
public:
- PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
- mojom::PrefStoreRequest request);
+ explicit PrefStoreImpl(scoped_refptr<::PrefStore> pref_store);
~PrefStoreImpl() override;
- // The created instance is registered in and owned by the
- // |mojom::PrefStoreRegistry|.
- static std::unique_ptr<PrefStoreImpl> Create(
- mojom::PrefStoreRegistry* registry_ptr,
- scoped_refptr<::PrefStore> pref_store,
- PrefValueStore::PrefStoreType type);
+ mojom::PrefStoreConnectionPtr AddObserver(
+ const std::vector<std::string>& prefs_to_observe);
private:
class Observer;
@@ -39,10 +34,6 @@ class PrefStoreImpl : public ::PrefStore::Observer, public mojom::PrefStore {
void OnPrefValueChanged(const std::string& key) override;
void OnInitializationCompleted(bool succeeded) override;
- // prefs::mojom::PrefStore:
- void AddObserver(const std::vector<std::string>& prefs_to_observe,
- AddObserverCallback callback) override;
-
// The backing store we observer for changes.
scoped_refptr<::PrefStore> backing_pref_store_;
@@ -54,11 +45,9 @@ class PrefStoreImpl : public ::PrefStore::Observer, public mojom::PrefStore {
// OnInitializationCompleted was called.
bool backing_pref_store_initialized_;
- mojo::Binding<mojom::PrefStore> binding_;
-
DISALLOW_COPY_AND_ASSIGN(PrefStoreImpl);
};
} // namespace prefs
-#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+#endif // SERVICES_PREFERENCES_PREF_STORE_IMPL_H_
diff --git a/chromium/services/preferences/pref_store_impl_unittest.cc b/chromium/services/preferences/pref_store_impl_unittest.cc
new file mode 100644
index 00000000000..6480d48b27e
--- /dev/null
+++ b/chromium/services/preferences/pref_store_impl_unittest.cc
@@ -0,0 +1,305 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/preferences/pref_store_impl.h"
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/prefs/value_map_pref_store.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/cpp/pref_store_client.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::WithoutArgs;
+
+namespace prefs {
+namespace {
+
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+class MockPrefStore : public ValueMapPrefStore {
+ public:
+ bool IsInitializationComplete() const override {
+ return initialized_ && success_;
+ }
+
+ void AddObserver(PrefStore::Observer* observer) override {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(PrefStore::Observer* observer) override {
+ observers_.RemoveObserver(observer);
+ }
+
+ void CompleteInitialization(bool success) {
+ initialized_ = true;
+ success_ = success;
+ for (auto& observer : observers_) {
+ // Some pref stores report completing initialization more than once. Test
+ // that additional calls are ignored.
+ observer.OnInitializationCompleted(success);
+ observer.OnInitializationCompleted(success);
+ }
+ }
+
+ void SetValue(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) override {
+ ValueMapPrefStore::SetValue(key, std::move(value), flags);
+ for (auto& observer : observers_) {
+ observer.OnPrefValueChanged(key);
+ }
+ }
+
+ private:
+ ~MockPrefStore() override = default;
+
+ bool initialized_ = false;
+ bool success_ = false;
+ base::ObserverList<PrefStore::Observer, true> observers_;
+};
+
+constexpr char kKey[] = "path.to.key";
+constexpr char kOtherKey[] = "path.to.other_key";
+
+void ExpectInitializationComplete(PrefStore* pref_store, bool success) {
+ PrefStoreObserverMock observer;
+ pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged("")).Times(0);
+ EXPECT_CALL(observer, OnInitializationCompleted(success))
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ pref_store->RemoveObserver(&observer);
+}
+
+void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
+ PrefStoreObserverMock observer;
+ pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(key.as_string()))
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ pref_store->RemoveObserver(&observer);
+}
+
+class PrefStoreImplTest : public testing::Test {
+ public:
+ PrefStoreImplTest() = default;
+
+ // testing::Test:
+ void TearDown() override {
+ pref_store_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ impl_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateImpl(
+ scoped_refptr<PrefStore> backing_pref_store,
+ std::vector<std::string> observed_prefs = std::vector<std::string>()) {
+ impl_ = base::MakeUnique<PrefStoreImpl>(std::move(backing_pref_store));
+
+ if (observed_prefs.empty())
+ observed_prefs.insert(observed_prefs.end(), {kKey, kOtherKey});
+ pref_store_ = make_scoped_refptr(
+ new PrefStoreClient(impl_->AddObserver(observed_prefs)));
+ }
+
+ PrefStore* pref_store() { return pref_store_.get(); }
+
+ private:
+ base::MessageLoop message_loop_;
+
+ std::unique_ptr<PrefStoreImpl> impl_;
+
+ scoped_refptr<PrefStore> pref_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreImplTest);
+};
+
+TEST_F(PrefStoreImplTest, InitializationSuccess) {
+ auto backing_pref_store = make_scoped_refptr(new MockPrefStore());
+ backing_pref_store->SetValue(kKey, base::MakeUnique<base::Value>("value"), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+
+ backing_pref_store->CompleteInitialization(true);
+ ExpectInitializationComplete(pref_store(), true);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+}
+
+TEST_F(PrefStoreImplTest, InitializationFailure) {
+ auto backing_pref_store = make_scoped_refptr(new MockPrefStore());
+ backing_pref_store->SetValue(kKey, base::MakeUnique<base::Value>("value"), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+
+ backing_pref_store->CompleteInitialization(false);
+ ExpectInitializationComplete(pref_store(), false);
+
+ // TODO(sammc): Should IsInitializationComplete() return false?
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+}
+
+TEST_F(PrefStoreImplTest, ValueChangesBeforeInitializationCompletes) {
+ auto backing_pref_store = make_scoped_refptr(new MockPrefStore());
+ CreateImpl(backing_pref_store);
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ backing_pref_store->CompleteInitialization(true);
+
+ // The update occurs before initialization has completed, so should not
+ // trigger notifications to client observers, but the value should be
+ // observable once initialization completes.
+ ExpectInitializationComplete(pref_store(), true);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PrefStoreImplTest, InitialValue) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PrefStoreImplTest, InitialValueWithoutPathExpansion) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PrefStoreImplTest, WriteObservedByClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PrefStoreImplTest, WriteToUnregisteredPrefNotObservedByClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ CreateImpl(backing_pref_store, {kKey});
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ backing_pref_store->SetValue(kOtherKey, base::MakeUnique<base::Value>(123),
+ 0);
+ backing_pref_store->SetValue(kKey, base::MakeUnique<base::Value>("value"), 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+ EXPECT_FALSE(pref_store()->GetValue(kOtherKey, nullptr));
+}
+
+TEST_F(PrefStoreImplTest, WriteWithoutPathExpansionObservedByClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PrefStoreImplTest, RemoveObservedByClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+ backing_pref_store->RemoveValue(kKey, 0);
+
+ // This should be a no-op and shouldn't trigger a notification for the other
+ // client.
+ backing_pref_store->RemoveValue(kKey, 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+ EXPECT_FALSE(pref_store()->GetValue(kKey, &output));
+}
+
+TEST_F(PrefStoreImplTest, RemoveOfUnregisteredPrefNotObservedByClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ backing_pref_store->SetValue(kOtherKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store, {kKey});
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ backing_pref_store->RemoveValue(kOtherKey, 0);
+ backing_pref_store->RemoveValue(kKey, 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+}
+
+TEST_F(PrefStoreImplTest, RemoveWithoutPathExpansionObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ ASSERT_TRUE(pref_store()->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+
+ base::Value* mutable_value = nullptr;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ ASSERT_TRUE(backing_pref_store->GetMutableValue(kKey, &mutable_value));
+ base::DictionaryValue* mutable_dict = nullptr;
+ ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict));
+ mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr);
+ backing_pref_store->ReportValueChanged(kKey, 0);
+
+ ExpectPrefChange(pref_store(), kKey);
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ const base::DictionaryValue* dict_value = nullptr;
+ ASSERT_TRUE(output->GetAsDictionary(&dict_value));
+ EXPECT_TRUE(dict_value->empty());
+}
+
+} // namespace
+} // namespace prefs
diff --git a/chromium/services/preferences/pref_store_manager_impl.cc b/chromium/services/preferences/pref_store_manager_impl.cc
index 288e6496e4a..1e24c372e52 100644
--- a/chromium/services/preferences/pref_store_manager_impl.cc
+++ b/chromium/services/preferences/pref_store_manager_impl.cc
@@ -10,133 +10,102 @@
#include "base/memory/ref_counted.h"
#include "base/stl_util.h"
#include "base/threading/sequenced_worker_pool.h"
-#include "components/prefs/default_pref_store.h"
+#include "components/prefs/pref_registry.h"
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/preferences/persistent_pref_store_factory.h"
#include "services/preferences/persistent_pref_store_impl.h"
-#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
#include "services/preferences/scoped_pref_connection_builder.h"
+#include "services/preferences/shared_pref_registry.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
+#include "services/service_manager/public/cpp/service_context.h"
namespace prefs {
+class PrefStoreManagerImpl::ConnectorConnection
+ : public mojom::PrefStoreConnector {
+ public:
+ ConnectorConnection(PrefStoreManagerImpl* owner,
+ const service_manager::BindSourceInfo& source_info)
+ : owner_(owner), source_info_(source_info) {}
+
+ void Connect(
+ mojom::PrefRegistryPtr pref_registry,
+ ConnectCallback callback) override {
+ auto connection = owner_->shared_pref_registry_->CreateConnectionBuilder(
+ std::move(pref_registry), source_info_.identity, std::move(callback));
+ if (owner_->persistent_pref_store_ &&
+ owner_->persistent_pref_store_->initialized()) {
+ connection->ProvidePersistentPrefStore(
+ owner_->persistent_pref_store_.get());
+ } else {
+ owner_->pending_persistent_connections_.push_back(connection);
+ }
+ if (owner_->incognito_persistent_pref_store_underlay_) {
+ if (owner_->incognito_persistent_pref_store_underlay_->initialized()) {
+ connection->ProvideIncognitoPersistentPrefStoreUnderlay(
+ owner_->incognito_persistent_pref_store_underlay_.get());
+ } else {
+ owner_->pending_persistent_incognito_connections_.push_back(connection);
+ }
+ }
+ connection->ProvidePrefStoreConnections(owner_->read_only_pref_stores_);
+ }
+
+ private:
+ PrefStoreManagerImpl* const owner_;
+ const service_manager::BindSourceInfo source_info_;
+};
+
PrefStoreManagerImpl::PrefStoreManagerImpl(
- std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
- scoped_refptr<base::SequencedWorkerPool> worker_pool)
- : expected_pref_stores_(std::move(expected_pref_stores)),
- init_binding_(this),
- defaults_(new DefaultPrefStore),
- defaults_wrapper_(base::MakeUnique<PrefStoreImpl>(
- defaults_,
- mojo::MakeRequest(&pref_store_ptrs_[PrefValueStore::DEFAULT_STORE]))),
- worker_pool_(std::move(worker_pool)) {
- DCHECK(
- base::ContainsValue(expected_pref_stores_, PrefValueStore::USER_STORE) &&
- base::ContainsValue(expected_pref_stores_, PrefValueStore::DEFAULT_STORE))
- << "expected_pref_stores must always include PrefValueStore::USER_STORE "
- "and PrefValueStore::DEFAULT_STORE.";
- // The user store is not actually connected to in the implementation, but
- // accessed directly.
- expected_pref_stores_.erase(PrefValueStore::USER_STORE);
+ PrefStore* managed_prefs,
+ PrefStore* supervised_user_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PersistentPrefStore* incognito_user_prefs_underlay,
+ PrefStore* recommended_prefs,
+ PrefRegistry* pref_registry)
+ : shared_pref_registry_(base::MakeUnique<SharedPrefRegistry>(
+ make_scoped_refptr(pref_registry))),
+ weak_factory_(this) {
+ // This store is done in-process so it's already "registered":
registry_.AddInterface<prefs::mojom::PrefStoreConnector>(
base::Bind(&PrefStoreManagerImpl::BindPrefStoreConnectorRequest,
base::Unretained(this)));
- registry_.AddInterface<prefs::mojom::PrefStoreRegistry>(
- base::Bind(&PrefStoreManagerImpl::BindPrefStoreRegistryRequest,
- base::Unretained(this)));
- registry_.AddInterface<prefs::mojom::PrefServiceControl>(
- base::Bind(&PrefStoreManagerImpl::BindPrefServiceControlRequest,
- base::Unretained(this)));
+ persistent_pref_store_ = base::MakeUnique<PersistentPrefStoreImpl>(
+ make_scoped_refptr(user_prefs),
+ base::BindOnce(&PrefStoreManagerImpl::OnPersistentPrefStoreReady,
+ base::Unretained(this)));
+ if (incognito_user_prefs_underlay) {
+ incognito_persistent_pref_store_underlay_ =
+ base::MakeUnique<PersistentPrefStoreImpl>(
+ make_scoped_refptr(user_prefs),
+ base::BindOnce(
+ &PrefStoreManagerImpl::OnIncognitoPersistentPrefStoreReady,
+ base::Unretained(this)));
+ }
+ RegisterPrefStore(PrefValueStore::MANAGED_STORE, managed_prefs);
+ RegisterPrefStore(PrefValueStore::SUPERVISED_USER_STORE,
+ supervised_user_prefs);
+ RegisterPrefStore(PrefValueStore::EXTENSION_STORE, extension_prefs);
+ RegisterPrefStore(PrefValueStore::COMMAND_LINE_STORE, command_line_prefs);
+ RegisterPrefStore(PrefValueStore::RECOMMENDED_STORE, recommended_prefs);
}
PrefStoreManagerImpl::~PrefStoreManagerImpl() = default;
-void PrefStoreManagerImpl::Register(PrefValueStore::PrefStoreType type,
- mojom::PrefStorePtr pref_store_ptr) {
- if (expected_pref_stores_.count(type) == 0) {
- LOG(WARNING) << "Not registering unexpected pref store: " << type;
- return;
- }
- DVLOG(1) << "Registering pref store: " << type;
- pref_store_ptr.set_connection_error_handler(
- base::Bind(&PrefStoreManagerImpl::OnPrefStoreDisconnect,
- base::Unretained(this), type));
- auto it = pending_connections_.find(type);
- if (it != pending_connections_.end()) {
- for (const auto& connection : it->second)
- connection->ProvidePrefStoreConnection(type, pref_store_ptr.get());
- pending_connections_.erase(it);
- }
-
- const bool success =
- pref_store_ptrs_.insert(std::make_pair(type, std::move(pref_store_ptr)))
- .second;
- DCHECK(success) << "The same pref store registered twice: " << type;
-}
-
-void PrefStoreManagerImpl::Connect(
- mojom::PrefRegistryPtr pref_registry,
- const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
- ConnectCallback callback) {
- std::set<PrefValueStore::PrefStoreType> required_remote_types;
- for (auto type : expected_pref_stores_) {
- if (!base::ContainsValue(already_connected_types, type)) {
- required_remote_types.insert(type);
- }
- }
- auto connection = base::MakeRefCounted<ScopedPrefConnectionBuilder>(
- std::move(pref_registry->registrations), std::move(required_remote_types),
- std::move(callback));
- if (persistent_pref_store_ && persistent_pref_store_->initialized()) {
- connection->ProvidePersistentPrefStore(persistent_pref_store_.get());
- } else {
- pending_persistent_connections_.push_back(connection);
- }
- auto remaining_remote_types =
- connection->ProvidePrefStoreConnections(pref_store_ptrs_);
- for (auto type : remaining_remote_types) {
- pending_connections_[type].push_back(connection);
- }
+base::OnceClosure PrefStoreManagerImpl::ShutDownClosure() {
+ return base::BindOnce(&PrefStoreManagerImpl::ShutDown,
+ weak_factory_.GetWeakPtr());
}
void PrefStoreManagerImpl::BindPrefStoreConnectorRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefStoreConnectorRequest request) {
- connector_bindings_.AddBinding(this, std::move(request));
-}
-
-void PrefStoreManagerImpl::BindPrefStoreRegistryRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefStoreRegistryRequest request) {
- registry_bindings_.AddBinding(this, std::move(request));
-}
-
-void PrefStoreManagerImpl::BindPrefServiceControlRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefServiceControlRequest request) {
- if (init_binding_.is_bound()) {
- LOG(ERROR)
- << "Pref service received unexpected control interface connection from "
- << source_info.identity.name();
- return;
- }
-
- init_binding_.Bind(std::move(request));
-}
-
-void PrefStoreManagerImpl::Init(
- mojom::PersistentPrefStoreConfigurationPtr configuration) {
- DCHECK(!persistent_pref_store_);
-
- persistent_pref_store_ = CreatePersistentPrefStore(
- std::move(configuration), worker_pool_.get(),
- base::Bind(&PrefStoreManagerImpl::OnPersistentPrefStoreReady,
- base::Unretained(this)));
- DCHECK(persistent_pref_store_);
- if (persistent_pref_store_->initialized()) {
- OnPersistentPrefStoreReady();
- }
+ prefs::mojom::PrefStoreConnectorRequest request,
+ const service_manager::BindSourceInfo& source_info) {
+ connector_bindings_.AddBinding(
+ base::MakeUnique<ConnectorConnection>(this, source_info),
+ std::move(request));
}
void PrefStoreManagerImpl::OnStart() {}
@@ -145,14 +114,8 @@ void PrefStoreManagerImpl::OnBindInterface(
const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
- registry_.BindInterface(source_info, interface_name,
- std::move(interface_pipe));
-}
-
-void PrefStoreManagerImpl::OnPrefStoreDisconnect(
- PrefValueStore::PrefStoreType type) {
- DVLOG(1) << "Deregistering pref store: " << type;
- pref_store_ptrs_.erase(type);
+ registry_.BindInterface(interface_name, std::move(interface_pipe),
+ source_info);
}
void PrefStoreManagerImpl::OnPersistentPrefStoreReady() {
@@ -162,4 +125,27 @@ void PrefStoreManagerImpl::OnPersistentPrefStoreReady() {
pending_persistent_connections_.clear();
}
+void PrefStoreManagerImpl::OnIncognitoPersistentPrefStoreReady() {
+ DVLOG(1) << "Incognito PersistentPrefStore ready";
+ for (const auto& connection : pending_persistent_connections_)
+ connection->ProvideIncognitoPersistentPrefStoreUnderlay(
+ incognito_persistent_pref_store_underlay_.get());
+ pending_persistent_incognito_connections_.clear();
+}
+
+void PrefStoreManagerImpl::RegisterPrefStore(PrefValueStore::PrefStoreType type,
+ PrefStore* pref_store) {
+ if (!pref_store)
+ return;
+
+ read_only_pref_stores_.emplace(
+ type, base::MakeUnique<PrefStoreImpl>(make_scoped_refptr(pref_store)));
+}
+
+void PrefStoreManagerImpl::ShutDown() {
+ read_only_pref_stores_.clear();
+ persistent_pref_store_.reset();
+ context()->QuitNow();
+}
+
} // namespace prefs
diff --git a/chromium/services/preferences/pref_store_manager_impl.h b/chromium/services/preferences/pref_store_manager_impl.h
index c1b0ae83ebe..fa5ea19ba99 100644
--- a/chromium/services/preferences/pref_store_manager_impl.h
+++ b/chromium/services/preferences/pref_store_manager_impl.h
@@ -15,17 +15,19 @@
#include "base/memory/ref_counted.h"
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
-class DefaultPrefStore;
+class PrefRegistry;
-namespace base {
-class SequencedWorkerPool;
+namespace service_manager {
+struct BindSourceInfo;
}
namespace prefs {
+class SharedPrefRegistry;
class PersistentPrefStoreImpl;
class PrefStoreImpl;
class ScopedPrefConnectionBuilder;
@@ -34,46 +36,26 @@ class ScopedPrefConnectionBuilder;
// and the pref stores that store those preferences. Pref stores use the
// |PrefStoreRegistry| interface to register themselves with the manager and
// clients use the |PrefStoreConnector| interface to connect to these stores.
-class PrefStoreManagerImpl : public mojom::PrefStoreRegistry,
- public mojom::PrefStoreConnector,
- public mojom::PrefServiceControl,
- public service_manager::Service {
+class PrefStoreManagerImpl : public service_manager::Service {
public:
- // Only replies to Connect calls when all |expected_pref_stores| have
- // registered. |expected_pref_stores| must contain
- // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE for
- // consistency, as the service always registers these
- // internally. |worker_pool| is used for any I/O performed by the service.
- PrefStoreManagerImpl(
- std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
- scoped_refptr<base::SequencedWorkerPool> worker_pool);
+ PrefStoreManagerImpl(PrefStore* managed_prefs,
+ PrefStore* supervised_user_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PersistentPrefStore* incognito_user_prefs_underlay,
+ PrefStore* recommended_prefs,
+ PrefRegistry* pref_registry);
~PrefStoreManagerImpl() override;
+ base::OnceClosure ShutDownClosure();
+
private:
- // mojom::PrefStoreRegistry:
- void Register(PrefValueStore::PrefStoreType type,
- mojom::PrefStorePtr pref_store_ptr) override;
-
- // mojom::PrefStoreConnector: |already_connected_types| must not include
- // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE as these must
- // always be accessed through the service.
- void Connect(
- mojom::PrefRegistryPtr pref_registry,
- const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
- ConnectCallback callback) override;
+ class ConnectorConnection;
void BindPrefStoreConnectorRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefStoreConnectorRequest request);
- void BindPrefStoreRegistryRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefStoreRegistryRequest request);
- void BindPrefServiceControlRequest(
- const service_manager::BindSourceInfo& source_info,
- prefs::mojom::PrefServiceControlRequest request);
-
- // PrefServiceControl:
- void Init(mojom::PersistentPrefStoreConfigurationPtr configuration) override;
+ prefs::mojom::PrefStoreConnectorRequest request,
+ const service_manager::BindSourceInfo& source_info);
// service_manager::Service:
void OnStart() override;
@@ -81,39 +63,35 @@ class PrefStoreManagerImpl : public mojom::PrefStoreRegistry,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
- // Called when a PrefStore previously registered using |Register| disconnects.
- void OnPrefStoreDisconnect(PrefValueStore::PrefStoreType type);
-
void OnPersistentPrefStoreReady();
+ void OnIncognitoPersistentPrefStoreReady();
+
+ void RegisterPrefStore(PrefValueStore::PrefStoreType type,
+ PrefStore* pref_store);
- // PrefStores that need to register before replying to any Connect calls. This
- // does not include the PersistentPrefStore, which is handled separately.
- std::set<PrefValueStore::PrefStoreType> expected_pref_stores_;
+ void ShutDown();
- // Registered pref stores.
- std::unordered_map<PrefValueStore::PrefStoreType, mojom::PrefStorePtr>
- pref_store_ptrs_;
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ std::unique_ptr<PrefStoreImpl>>
+ read_only_pref_stores_;
- mojo::BindingSet<mojom::PrefStoreConnector> connector_bindings_;
- mojo::BindingSet<mojom::PrefStoreRegistry> registry_bindings_;
+ mojo::StrongBindingSet<mojom::PrefStoreConnector> connector_bindings_;
std::unique_ptr<PersistentPrefStoreImpl> persistent_pref_store_;
- mojo::Binding<mojom::PrefServiceControl> init_binding_;
+ std::unique_ptr<PersistentPrefStoreImpl>
+ incognito_persistent_pref_store_underlay_;
- const scoped_refptr<DefaultPrefStore> defaults_;
- const std::unique_ptr<PrefStoreImpl> defaults_wrapper_;
+ const std::unique_ptr<SharedPrefRegistry> shared_pref_registry_;
- // The same |ScopedPrefConnectionBuilder| instance may appear multiple times
- // in |pending_connections_|, once per type of pref store it's waiting for,
- // and at most once in |pending_persistent_connections_|.
- std::unordered_map<PrefValueStore::PrefStoreType,
- std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>>
- pending_connections_;
std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>
pending_persistent_connections_;
+ std::vector<scoped_refptr<ScopedPrefConnectionBuilder>>
+ pending_persistent_incognito_connections_;
- const scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ service_manager::BinderRegistryWithArgs<
+ const service_manager::BindSourceInfo&>
+ registry_;
- service_manager::BinderRegistry registry_;
+ base::WeakPtrFactory<PrefStoreManagerImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrefStoreManagerImpl);
};
diff --git a/chromium/services/preferences/public/cpp/BUILD.gn b/chromium/services/preferences/public/cpp/BUILD.gn
index 53ead75b2c5..fb4d1ce6c26 100644
--- a/chromium/services/preferences/public/cpp/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/BUILD.gn
@@ -12,14 +12,10 @@ source_set("cpp") {
"pref_registry_serializer.h",
"pref_service_factory.cc",
"pref_service_factory.h",
- "pref_store_adapter.cc",
- "pref_store_adapter.h",
"pref_store_client.cc",
"pref_store_client.h",
"pref_store_client_mixin.cc",
"pref_store_client_mixin.h",
- "pref_store_impl.cc",
- "pref_store_impl.h",
"scoped_pref_update.cc",
"scoped_pref_update.h",
]
@@ -40,11 +36,14 @@ source_set("cpp") {
source_set("service_main") {
deps = [
"//base",
+ "//components/keyed_service/core",
"//components/prefs",
"//services/preferences",
"//services/service_manager/public/cpp",
]
sources = [
+ "in_process_service_factory.cc",
+ "in_process_service_factory.h",
"pref_service_main.cc",
"pref_service_main.h",
]
diff --git a/chromium/services/preferences/public/cpp/DEPS b/chromium/services/preferences/public/cpp/DEPS
index 45e227dd6d0..afbd4250414 100644
--- a/chromium/services/preferences/public/cpp/DEPS
+++ b/chromium/services/preferences/public/cpp/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/keyed_service/core",
"+components/prefs",
"-services/preferences",
"+services/preferences/public",
diff --git a/chromium/services/preferences/public/cpp/dictionary_value_update.cc b/chromium/services/preferences/public/cpp/dictionary_value_update.cc
index 513fe611bc8..afd7ae85450 100644
--- a/chromium/services/preferences/public/cpp/dictionary_value_update.cc
+++ b/chromium/services/preferences/public/cpp/dictionary_value_update.cc
@@ -79,8 +79,8 @@ std::unique_ptr<DictionaryValueUpdate> DictionaryValueUpdate::SetDictionary(
base::StringPiece path,
std::unique_ptr<base::DictionaryValue> in_value) {
RecordPath(path);
- base::DictionaryValue* dictionary_value = in_value.get();
- value_->Set(path, std::move(in_value));
+ base::DictionaryValue* dictionary_value =
+ value_->SetDictionary(path, std::move(in_value));
return base::MakeUnique<DictionaryValueUpdate>(
report_update_, dictionary_value, ConcatPath(path_, path));
@@ -133,8 +133,8 @@ DictionaryValueUpdate::SetDictionaryWithoutPathExpansion(
base::StringPiece path,
std::unique_ptr<base::DictionaryValue> in_value) {
RecordKey(path);
- base::DictionaryValue* dictionary_value = in_value.get();
- value_->SetWithoutPathExpansion(path, std::move(in_value));
+ base::DictionaryValue* dictionary_value =
+ value_->SetDictionaryWithoutPathExpansion(path, std::move(in_value));
std::vector<std::string> full_path = path_;
full_path.push_back(path.as_string());
diff --git a/chromium/services/preferences/public/cpp/in_process_service_factory.cc b/chromium/services/preferences/public/cpp/in_process_service_factory.cc
new file mode 100644
index 00000000000..4127d29d832
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/in_process_service_factory.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "components/prefs/pref_registry.h"
+#include "services/preferences/public/cpp/pref_service_main.h"
+
+namespace prefs {
+namespace {
+
+static std::unique_ptr<service_manager::Service> WeakCreatePrefService(
+ base::WeakPtr<InProcessPrefServiceFactory> weak_factory) {
+ if (!weak_factory)
+ return base::MakeUnique<service_manager::Service>();
+
+ return weak_factory->CreatePrefService();
+}
+
+} // namespace
+
+// Registers all provided |PrefStore|s with the pref service. The pref stores
+// remaining registered for the life time of |this|.
+class InProcessPrefServiceFactory::RegisteringDelegate
+ : public PrefValueStore::Delegate {
+ public:
+ RegisteringDelegate(base::WeakPtr<InProcessPrefServiceFactory> factory)
+ : factory_(std::move(factory)) {}
+
+ // PrefValueStore::Delegate:
+ void Init(PrefStore* managed_prefs,
+ PrefStore* supervised_user_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PrefStore* user_prefs,
+ PrefStore* recommended_prefs,
+ PrefStore* default_prefs,
+ PrefNotifier* pref_notifier) override {
+ if (!factory_)
+ return;
+
+ factory_->managed_prefs_ = make_scoped_refptr(managed_prefs);
+ factory_->supervised_user_prefs_ =
+ make_scoped_refptr(supervised_user_prefs);
+ factory_->extension_prefs_ = make_scoped_refptr(extension_prefs);
+ factory_->command_line_prefs_ = make_scoped_refptr(command_line_prefs);
+ factory_->user_prefs_ =
+ make_scoped_refptr(static_cast<PersistentPrefStore*>(user_prefs));
+ factory_->recommended_prefs_ = make_scoped_refptr(recommended_prefs);
+ }
+
+ void InitIncognitoUnderlay(
+ PersistentPrefStore* incognito_user_prefs_underlay) override {
+ factory_->incognito_user_prefs_underlay_ =
+ make_scoped_refptr(incognito_user_prefs_underlay);
+ }
+
+ void InitPrefRegistry(PrefRegistry* pref_registry) override {
+ factory_->pref_registry_ = make_scoped_refptr(pref_registry);
+ }
+
+ void UpdateCommandLinePrefStore(PrefStore* command_line_prefs) override {
+ // TODO(tibell): Once we have a way to deregister stores, do so here. At the
+ // moment only local state uses this and local state doesn't use the pref
+ // service yet.
+ }
+
+ private:
+ base::WeakPtr<InProcessPrefServiceFactory> factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegisteringDelegate);
+};
+
+InProcessPrefServiceFactory::InProcessPrefServiceFactory()
+ : weak_factory_(this) {}
+
+InProcessPrefServiceFactory::~InProcessPrefServiceFactory() {
+ if (quit_closure_)
+ std::move(quit_closure_).Run();
+}
+
+std::unique_ptr<PrefValueStore::Delegate>
+InProcessPrefServiceFactory::CreateDelegate() {
+ return base::MakeUnique<RegisteringDelegate>(weak_factory_.GetWeakPtr());
+}
+
+base::Callback<std::unique_ptr<service_manager::Service>()>
+InProcessPrefServiceFactory::CreatePrefServiceFactory() {
+ return base::Bind(&WeakCreatePrefService, weak_factory_.GetWeakPtr());
+}
+
+std::unique_ptr<service_manager::Service>
+InProcessPrefServiceFactory::CreatePrefService() {
+ auto result = prefs::CreatePrefService(
+ managed_prefs_.get(), supervised_user_prefs_.get(),
+ extension_prefs_.get(), command_line_prefs_.get(), user_prefs_.get(),
+ incognito_user_prefs_underlay_.get(), recommended_prefs_.get(),
+ pref_registry_.get());
+ quit_closure_ = std::move(result.second);
+ return std::move(result.first);
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/in_process_service_factory.h b/chromium/services/preferences/public/cpp/in_process_service_factory.h
new file mode 100644
index 00000000000..10bea7d9195
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/in_process_service_factory.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_value_store.h"
+#include "services/service_manager/public/cpp/service.h"
+
+class PersistentPrefStore;
+class PrefRegistry;
+class PrefStore;
+
+namespace prefs {
+
+class InProcessPrefServiceFactory : public KeyedService {
+ public:
+ InProcessPrefServiceFactory();
+ ~InProcessPrefServiceFactory() override;
+
+ std::unique_ptr<PrefValueStore::Delegate> CreateDelegate();
+
+ base::Callback<std::unique_ptr<service_manager::Service>()>
+ CreatePrefServiceFactory();
+
+ std::unique_ptr<service_manager::Service> CreatePrefService();
+
+ private:
+ class RegisteringDelegate;
+
+ scoped_refptr<PrefStore> managed_prefs_;
+ scoped_refptr<PrefStore> supervised_user_prefs_;
+ scoped_refptr<PrefStore> extension_prefs_;
+ scoped_refptr<PrefStore> command_line_prefs_;
+ scoped_refptr<PersistentPrefStore> user_prefs_;
+ scoped_refptr<PersistentPrefStore> incognito_user_prefs_underlay_;
+ scoped_refptr<PrefStore> recommended_prefs_;
+ scoped_refptr<PrefRegistry> pref_registry_;
+
+ base::OnceClosure quit_closure_;
+
+ base::WeakPtrFactory<InProcessPrefServiceFactory> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessPrefServiceFactory);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_IN_PROCESS_SERVICE_FACTORY_H_
diff --git a/chromium/services/preferences/public/cpp/lib/util.cc b/chromium/services/preferences/public/cpp/lib/util.cc
index dcd9f32bfc4..493b8aab23f 100644
--- a/chromium/services/preferences/public/cpp/lib/util.cc
+++ b/chromium/services/preferences/public/cpp/lib/util.cc
@@ -10,6 +10,62 @@
#include "base/values.h"
namespace prefs {
+namespace {
+
+enum class MatchType { kNo, kExact, kPrefix };
+
+MatchType MatchPref(base::StringPiece string, base::StringPiece prefix) {
+ if (string.substr(0, prefix.size()) != prefix)
+ return MatchType::kNo;
+
+ if (string.size() == prefix.size())
+ return MatchType::kExact;
+
+ return string[prefix.size()] == '.' ? MatchType::kPrefix : MatchType::kNo;
+}
+
+std::unique_ptr<base::DictionaryValue> FilterPrefsImpl(
+ std::unique_ptr<base::DictionaryValue> prefs,
+ const std::set<std::string>& observed_prefs,
+ const std::string& prefix) {
+ if (!prefs)
+ return nullptr;
+
+ auto filtered_value = base::MakeUnique<base::DictionaryValue>();
+ std::string full_path = prefix;
+ for (auto& pref : *prefs) {
+ full_path.resize(prefix.size());
+ if (full_path.empty()) {
+ full_path = pref.first;
+ } else {
+ full_path.reserve(full_path.size() + 1 + pref.first.size());
+ full_path += ".";
+ full_path += pref.first;
+ }
+ auto it = observed_prefs.lower_bound(full_path);
+ if (it == observed_prefs.end())
+ continue;
+
+ auto result = MatchPref(*it, full_path);
+ switch (result) {
+ case MatchType::kNo:
+ break;
+ case MatchType::kExact:
+ filtered_value->Set(pref.first, std::move(pref.second));
+ break;
+ case MatchType::kPrefix:
+ auto filtered_subpref =
+ FilterPrefsImpl(base::DictionaryValue::From(std::move(pref.second)),
+ observed_prefs, full_path);
+ if (filtered_subpref)
+ filtered_value->Set(pref.first, std::move(filtered_subpref));
+ break;
+ }
+ }
+ return filtered_value;
+}
+
+} // namespace
void SetValue(base::DictionaryValue* dictionary_value,
const std::vector<base::StringPiece>& path_components,
@@ -17,11 +73,8 @@ void SetValue(base::DictionaryValue* dictionary_value,
for (size_t i = 0; i < path_components.size() - 1; ++i) {
if (!dictionary_value->GetDictionaryWithoutPathExpansion(
path_components[i], &dictionary_value)) {
- auto new_dict_value_owner = base::MakeUnique<base::DictionaryValue>();
- auto* new_dict_value = new_dict_value_owner.get();
- dictionary_value->SetWithoutPathExpansion(
- path_components[i], std::move(new_dict_value_owner));
- dictionary_value = new_dict_value;
+ dictionary_value = dictionary_value->SetDictionaryWithoutPathExpansion(
+ path_components[i], base::MakeUnique<base::DictionaryValue>());
}
}
const auto& key = path_components.back();
@@ -31,4 +84,10 @@ void SetValue(base::DictionaryValue* dictionary_value,
dictionary_value->RemoveWithoutPathExpansion(key, nullptr);
}
+std::unique_ptr<base::DictionaryValue> FilterPrefs(
+ std::unique_ptr<base::DictionaryValue> prefs,
+ const std::set<std::string>& observed_prefs) {
+ return FilterPrefsImpl(std::move(prefs), observed_prefs, std::string());
+}
+
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/lib/util.h b/chromium/services/preferences/public/cpp/lib/util.h
index 3e3c88adc82..213497b2c26 100644
--- a/chromium/services/preferences/public/cpp/lib/util.h
+++ b/chromium/services/preferences/public/cpp/lib/util.h
@@ -6,6 +6,8 @@
#define SERVICES_PREFERENCES_PUBLIC_CPP_LIB_UTIL_H_
#include <memory>
+#include <set>
+#include <string>
#include <vector>
#include "base/strings/string_piece.h"
@@ -23,6 +25,11 @@ void SetValue(base::DictionaryValue* dictionary_value,
const std::vector<base::StringPiece>& path_components,
std::unique_ptr<base::Value> value);
+// Filters |prefs| to paths contained within |observed_prefs|.
+std::unique_ptr<base::DictionaryValue> FilterPrefs(
+ std::unique_ptr<base::DictionaryValue> prefs,
+ const std::set<std::string>& observed_prefs);
+
} // namespace prefs
#endif // SERVICES_PREFERENCES_PUBLIC_CPP_LIB_UTIL_H_
diff --git a/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc b/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc
index baf9aa1ab3f..3131d4ad2c3 100644
--- a/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc
+++ b/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc
@@ -59,23 +59,107 @@ void RemoveRedundantPaths(std::set<std::vector<std::string>>* updated_paths) {
} // namespace
-PersistentPrefStoreClient::PersistentPrefStoreClient(
- mojom::PrefStoreConnectorPtr connector,
- scoped_refptr<PrefRegistry> pref_registry,
- std::vector<PrefValueStore::PrefStoreType> already_connected_types)
- : connector_(std::move(connector)),
- pref_registry_(std::move(pref_registry)),
- already_connected_types_(std::move(already_connected_types)),
- weak_factory_(this) {
- DCHECK(connector_);
-}
+// A trie of writes that have been applied locally and sent to the service
+// backend, but have not been acked.
+class PersistentPrefStoreClient::InFlightWriteTrie {
+ public:
+ // Decision on what to do with writes incoming from the service.
+ enum class Decision {
+ // The write should be allowed.
+ kAllow,
+
+ // The write has already been superceded locally and should be ignored.
+ kIgnore,
+
+ // The write may have been partially superceded locally and should be
+ // ignored but an updated value is needed from the service.
+ kResolve
+ };
+
+ InFlightWriteTrie() = default;
+
+ void Add() {
+ std::vector<std::string> v;
+ Add(v.begin(), v.end());
+ }
+
+ template <typename It, typename Jt>
+ void Add(It path_start, Jt path_end) {
+ if (path_start == path_end) {
+ ++writes_in_flight_;
+ return;
+ }
+ children_[*path_start].Add(path_start + 1, path_end);
+ }
+
+ bool Remove() {
+ std::vector<std::string> v;
+ return Remove(v.begin(), v.end());
+ }
+
+ template <typename It, typename Jt>
+ bool Remove(It path_start, Jt path_end) {
+ if (path_start == path_end) {
+ DCHECK_GT(writes_in_flight_, 0);
+ return --writes_in_flight_ == 0 && children_.empty();
+ }
+ auto it = children_.find(*path_start);
+ DCHECK(it != children_.end()) << *path_start;
+ auto removed = it->second.Remove(path_start + 1, path_end);
+ if (removed)
+ children_.erase(*path_start);
+
+ return children_.empty() && writes_in_flight_ == 0;
+ }
+
+ template <typename It, typename Jt>
+ Decision Lookup(It path_start, Jt path_end) {
+ if (path_start == path_end) {
+ if (children_.empty()) {
+ DCHECK_GT(writes_in_flight_, 0);
+ return Decision::kIgnore;
+ }
+ return Decision::kResolve;
+ }
+
+ if (writes_in_flight_ != 0) {
+ return Decision::kIgnore;
+ }
+ auto it = children_.find(*path_start);
+ if (it == children_.end()) {
+ return Decision::kAllow;
+ }
+
+ return it->second.Lookup(path_start + 1, path_end);
+ }
+
+ private:
+ std::map<std::string, InFlightWriteTrie> children_;
+ int writes_in_flight_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(InFlightWriteTrie);
+};
+
+struct PersistentPrefStoreClient::InFlightWrite {
+ std::string key;
+ std::vector<std::vector<std::string>> sub_pref_paths;
+};
PersistentPrefStoreClient::PersistentPrefStoreClient(
mojom::PersistentPrefStoreConnectionPtr connection)
: weak_factory_(this) {
- OnConnect(std::move(connection),
- std::unordered_map<PrefValueStore::PrefStoreType,
- prefs::mojom::PrefStoreConnectionPtr>());
+ read_error_ = connection->read_error;
+ read_only_ = connection->read_only;
+ pref_store_ = std::move(connection->pref_store);
+ if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
+ error_delegate_->OnError(read_error_);
+ error_delegate_.reset();
+ if (connection->pref_store_connection) {
+ Init(std::move(connection->pref_store_connection->initial_prefs), true,
+ std::move(connection->pref_store_connection->observer));
+ } else {
+ Init(nullptr, false, nullptr);
+ }
}
void PersistentPrefStoreClient::SetValue(const std::string& key,
@@ -123,9 +207,6 @@ void PersistentPrefStoreClient::SetValueSilently(
uint32_t flags) {
DCHECK(pref_store_);
GetMutableValues().Set(key, std::move(value));
- QueueWrite(key,
- std::set<std::vector<std::string>>{std::vector<std::string>{}},
- flags);
}
bool PersistentPrefStoreClient::ReadOnly() const {
@@ -138,35 +219,18 @@ PersistentPrefStore::PrefReadError PersistentPrefStoreClient::GetReadError()
}
PersistentPrefStore::PrefReadError PersistentPrefStoreClient::ReadPrefs() {
- mojom::PersistentPrefStoreConnectionPtr connection;
- std::unordered_map<PrefValueStore::PrefStoreType,
- prefs::mojom::PrefStoreConnectionPtr>
- other_pref_stores;
- mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_calls;
- bool success = connector_->Connect(SerializePrefRegistry(*pref_registry_),
- already_connected_types_, &connection,
- &other_pref_stores);
- DCHECK(success);
- pref_registry_ = nullptr;
- OnConnect(std::move(connection), std::move(other_pref_stores));
- return read_error_;
+ return GetReadError();
}
void PersistentPrefStoreClient::ReadPrefsAsync(
- ReadErrorDelegate* error_delegate) {
- error_delegate_.reset(error_delegate);
- connector_->Connect(SerializePrefRegistry(*pref_registry_),
- already_connected_types_,
- base::Bind(&PersistentPrefStoreClient::OnConnect,
- base::Unretained(this)));
- pref_registry_ = nullptr;
-}
+ ReadErrorDelegate* error_delegate) {}
-void PersistentPrefStoreClient::CommitPendingWrite() {
+void PersistentPrefStoreClient::CommitPendingWrite(
+ base::OnceClosure done_callback) {
DCHECK(pref_store_);
if (!pending_writes_.empty())
FlushPendingWrites();
- pref_store_->CommitPendingWrite();
+ pref_store_->CommitPendingWrite(std::move(done_callback));
}
void PersistentPrefStoreClient::SchedulePendingLossyWrites() {
@@ -183,28 +247,7 @@ PersistentPrefStoreClient::~PersistentPrefStoreClient() {
if (!pref_store_)
return;
- CommitPendingWrite();
-}
-
-void PersistentPrefStoreClient::OnConnect(
- mojom::PersistentPrefStoreConnectionPtr connection,
- std::unordered_map<PrefValueStore::PrefStoreType,
- prefs::mojom::PrefStoreConnectionPtr>
- other_pref_stores) {
- connector_.reset();
- read_error_ = connection->read_error;
- read_only_ = connection->read_only;
- pref_store_ = std::move(connection->pref_store);
- if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
- error_delegate_->OnError(read_error_);
- error_delegate_.reset();
-
- if (connection->pref_store_connection) {
- Init(std::move(connection->pref_store_connection->initial_prefs), true,
- std::move(connection->pref_store_connection->observer));
- } else {
- Init(nullptr, false, nullptr);
- }
+ CommitPendingWrite(base::OnceClosure());
}
void PersistentPrefStoreClient::QueueWrite(
@@ -229,16 +272,24 @@ void PersistentPrefStoreClient::QueueWrite(
}
void PersistentPrefStoreClient::FlushPendingWrites() {
+ weak_factory_.InvalidateWeakPtrs();
+ if (pending_writes_.empty())
+ return;
+
std::vector<mojom::PrefUpdatePtr> updates;
+ std::vector<InFlightWrite> writes;
+
for (auto& pref : pending_writes_) {
auto update_value = mojom::PrefUpdateValue::New();
const base::Value* value = nullptr;
if (GetValue(pref.first, &value)) {
std::vector<mojom::SubPrefUpdatePtr> pref_updates;
+ std::vector<std::vector<std::string>> sub_pref_writes;
RemoveRedundantPaths(&pref.second.first);
for (const auto& path : pref.second.first) {
if (path.empty()) {
pref_updates.clear();
+ sub_pref_writes.clear();
break;
}
const base::Value* nested_value = LookupPath(value, path);
@@ -248,20 +299,78 @@ void PersistentPrefStoreClient::FlushPendingWrites() {
} else {
pref_updates.emplace_back(base::in_place, path, nullptr);
}
+ sub_pref_writes.push_back(path);
}
if (pref_updates.empty()) {
update_value->set_atomic_update(value->CreateDeepCopy());
+ writes.push_back({pref.first});
} else {
update_value->set_split_updates(std::move(pref_updates));
+ writes.push_back({pref.first, std::move(sub_pref_writes)});
}
} else {
update_value->set_atomic_update(nullptr);
+ writes.push_back({pref.first});
}
updates.emplace_back(base::in_place, pref.first, std::move(update_value),
pref.second.second);
}
pref_store_->SetValues(std::move(updates));
pending_writes_.clear();
+
+ for (const auto& write : writes) {
+ auto& trie = in_flight_writes_tries_[write.key];
+ if (write.sub_pref_paths.empty()) {
+ trie.Add();
+ } else {
+ for (const auto& subpref_update : write.sub_pref_paths) {
+ trie.Add(subpref_update.begin(), subpref_update.end());
+ }
+ }
+ }
+ in_flight_writes_queue_.push(std::move(writes));
+}
+
+void PersistentPrefStoreClient::OnPrefChangeAck() {
+ const auto& writes = in_flight_writes_queue_.front();
+ for (const auto& write : writes) {
+ auto it = in_flight_writes_tries_.find(write.key);
+ DCHECK(it != in_flight_writes_tries_.end()) << write.key;
+ bool remove = false;
+ if (write.sub_pref_paths.empty()) {
+ remove = it->second.Remove();
+ } else {
+ for (const auto& subpref_update : write.sub_pref_paths) {
+ remove =
+ it->second.Remove(subpref_update.begin(), subpref_update.end());
+ }
+ }
+ if (remove) {
+ in_flight_writes_tries_.erase(it);
+ }
+ }
+ in_flight_writes_queue_.pop();
+}
+
+bool PersistentPrefStoreClient::ShouldSkipWrite(
+ const std::string& key,
+ const std::vector<std::string>& path,
+ const base::Value* new_value) {
+ if (!pending_writes_.empty()) {
+ FlushPendingWrites();
+ }
+ auto it = in_flight_writes_tries_.find(key);
+ if (it == in_flight_writes_tries_.end()) {
+ return false;
+ }
+
+ auto decision = it->second.Lookup(path.begin(), path.end());
+ if (decision == InFlightWriteTrie::Decision::kAllow) {
+ return false;
+ }
+ if (decision == InFlightWriteTrie::Decision::kResolve)
+ pref_store_->RequestValue(key, path);
+ return true;
}
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/persistent_pref_store_client.h b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
index 67849f4245e..e00db150e63 100644
--- a/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
+++ b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -23,8 +23,6 @@ namespace base {
class Value;
}
-class PrefRegistry;
-
namespace prefs {
// An implementation of PersistentPrefStore backed by a
@@ -32,11 +30,6 @@ namespace prefs {
class PersistentPrefStoreClient
: public PrefStoreClientMixin<PersistentPrefStore> {
public:
- PersistentPrefStoreClient(
- mojom::PrefStoreConnectorPtr connector,
- scoped_refptr<PrefRegistry> pref_registry,
- std::vector<PrefValueStore::PrefStoreType> already_connected_types);
-
explicit PersistentPrefStoreClient(
mojom::PersistentPrefStoreConnectionPtr connection);
@@ -60,7 +53,7 @@ class PersistentPrefStoreClient
PrefReadError GetReadError() const override;
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
- void CommitPendingWrite() override;
+ void CommitPendingWrite(base::OnceClosure done_callback) override;
void SchedulePendingLossyWrites() override;
void ClearMutableValues() override;
@@ -69,18 +62,21 @@ class PersistentPrefStoreClient
~PersistentPrefStoreClient() override;
private:
- void OnConnect(mojom::PersistentPrefStoreConnectionPtr connection,
- std::unordered_map<PrefValueStore::PrefStoreType,
- prefs::mojom::PrefStoreConnectionPtr>
- other_pref_stores);
+ class InFlightWriteTrie;
+ struct InFlightWrite;
void QueueWrite(const std::string& key,
std::set<std::vector<std::string>> path_components,
uint32_t flags);
void FlushPendingWrites();
- mojom::PrefStoreConnectorPtr connector_;
- scoped_refptr<PrefRegistry> pref_registry_;
+ // prefs::mojom::PreferenceObserver:
+ void OnPrefChangeAck() override;
+
+ bool ShouldSkipWrite(const std::string& key,
+ const std::vector<std::string>& path,
+ const base::Value* new_value) override;
+
bool read_only_ = false;
PrefReadError read_error_ = PersistentPrefStore::PREF_READ_ERROR_NONE;
mojom::PersistentPrefStorePtr pref_store_;
@@ -88,7 +84,9 @@ class PersistentPrefStoreClient
pending_writes_;
std::unique_ptr<ReadErrorDelegate> error_delegate_;
- std::vector<PrefValueStore::PrefStoreType> already_connected_types_;
+
+ std::queue<std::vector<InFlightWrite>> in_flight_writes_queue_;
+ std::map<std::string, InFlightWriteTrie> in_flight_writes_tries_;
base::WeakPtrFactory<PersistentPrefStoreClient> weak_factory_;
diff --git a/chromium/services/preferences/public/cpp/pref_registry_serializer.cc b/chromium/services/preferences/public/cpp/pref_registry_serializer.cc
index 484e8ab9aba..64ccbe59cbb 100644
--- a/chromium/services/preferences/public/cpp/pref_registry_serializer.cc
+++ b/chromium/services/preferences/public/cpp/pref_registry_serializer.cc
@@ -8,10 +8,20 @@
namespace prefs {
-mojom::PrefRegistryPtr SerializePrefRegistry(PrefRegistry& pref_registry) {
+mojom::PrefRegistryPtr SerializePrefRegistry(
+ const PrefRegistry& pref_registry) {
auto registry = mojom::PrefRegistry::New();
for (auto& pref : pref_registry) {
- registry->registrations.push_back(pref.first);
+ auto flags = pref_registry.GetRegistrationFlags(pref.first);
+ if (flags & PrefRegistry::PUBLIC) {
+ registry->public_registrations.emplace_back(mojom::PrefRegistration::New(
+ pref.first, pref.second->CreateDeepCopy(), flags));
+ } else {
+ registry->private_registrations.push_back(pref.first);
+ }
+ }
+ for (auto& pref : pref_registry.foreign_pref_keys()) {
+ registry->foreign_registrations.push_back(pref);
}
return registry;
}
diff --git a/chromium/services/preferences/public/cpp/pref_registry_serializer.h b/chromium/services/preferences/public/cpp/pref_registry_serializer.h
index 4e016ce9519..9df4eb5ed62 100644
--- a/chromium/services/preferences/public/cpp/pref_registry_serializer.h
+++ b/chromium/services/preferences/public/cpp/pref_registry_serializer.h
@@ -11,7 +11,7 @@ class PrefRegistry;
namespace prefs {
-mojom::PrefRegistryPtr SerializePrefRegistry(PrefRegistry& pref_registry);
+mojom::PrefRegistryPtr SerializePrefRegistry(const PrefRegistry& pref_registry);
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.cc b/chromium/services/preferences/public/cpp/pref_service_factory.cc
index 2f1f4316492..d7868021344 100644
--- a/chromium/services/preferences/public/cpp/pref_service_factory.cc
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.cc
@@ -5,6 +5,7 @@
#include "services/preferences/public/cpp/pref_service_factory.h"
#include "base/callback_helpers.h"
+#include "components/prefs/overlay_user_pref_store.h"
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_notifier_impl.h"
#include "components/prefs/pref_registry.h"
@@ -44,10 +45,28 @@ scoped_refptr<PrefStore> CreatePrefStoreClient(
mojom::PrefStoreConnectionPtr>* connections) {
auto pref_store_it = connections->find(store_type);
if (pref_store_it != connections->end()) {
- return make_scoped_refptr(
- new PrefStoreClient(std::move(pref_store_it->second)));
+ return base::MakeRefCounted<PrefStoreClient>(
+ std::move(pref_store_it->second));
+ }
+ return nullptr;
+}
+
+void OnPrefServiceInit(std::unique_ptr<PrefService> pref_service,
+ ConnectCallback callback,
+ bool success) {
+ if (success) {
+ callback.Run(std::move(pref_service));
} else {
- return nullptr;
+ callback.Run(nullptr);
+ }
+}
+
+void RegisterRemoteDefaults(PrefRegistry* pref_registry,
+ std::vector<mojom::PrefRegistrationPtr> defaults) {
+ for (auto& registration : defaults) {
+ pref_registry->SetDefaultForeignPrefValue(
+ registration->key, std::move(registration->default_value),
+ registration->flags);
}
}
@@ -57,6 +76,8 @@ void OnConnect(
scoped_refptr<PrefRegistry> pref_registry,
ConnectCallback callback,
mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ mojom::PersistentPrefStoreConnectionPtr incognito_connection,
+ std::vector<mojom::PrefRegistrationPtr> defaults,
std::unordered_map<PrefValueStore::PrefStoreType,
mojom::PrefStoreConnectionPtr> connections) {
scoped_refptr<PrefStore> managed_prefs =
@@ -69,20 +90,41 @@ void OnConnect(
CreatePrefStoreClient(PrefValueStore::COMMAND_LINE_STORE, &connections);
scoped_refptr<PrefStore> recommended_prefs =
CreatePrefStoreClient(PrefValueStore::RECOMMENDED_STORE, &connections);
- // TODO(crbug.com/719770): Once owning registrations are supported, pass the
- // default values of owned prefs to the service and connect to the service's
- // defaults pref store instead of using a local one.
+ RegisterRemoteDefaults(pref_registry.get(), std::move(defaults));
scoped_refptr<PersistentPrefStore> persistent_pref_store(
new PersistentPrefStoreClient(
std::move(persistent_pref_store_connection)));
+ // If in incognito mode, |persistent_pref_store| above will be a connection to
+ // an in-memory pref store and |incognito_connection| will refer to the
+ // underlying profile's user pref store.
+ scoped_refptr<PersistentPrefStore> user_pref_store =
+ incognito_connection
+ ? new OverlayUserPrefStore(
+ persistent_pref_store.get(),
+ new PersistentPrefStoreClient(std::move(incognito_connection)))
+ : persistent_pref_store;
PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
auto* pref_value_store = new PrefValueStore(
managed_prefs.get(), supervised_user_prefs.get(), extension_prefs.get(),
- command_line_prefs.get(), persistent_pref_store.get(),
- recommended_prefs.get(), pref_registry->defaults().get(), pref_notifier);
- callback.Run(base::MakeUnique<::PrefService>(
- pref_notifier, pref_value_store, persistent_pref_store.get(),
- pref_registry.get(), base::Bind(&DoNothingHandleReadError), true));
+ command_line_prefs.get(), user_pref_store.get(), recommended_prefs.get(),
+ pref_registry->defaults().get(), pref_notifier);
+ auto pref_service = base::MakeUnique<PrefService>(
+ pref_notifier, pref_value_store, user_pref_store.get(),
+ pref_registry.get(), base::Bind(&DoNothingHandleReadError), true);
+ switch (pref_service->GetInitializationStatus()) {
+ case PrefService::INITIALIZATION_STATUS_WAITING:
+ pref_service->AddPrefInitObserver(base::Bind(&OnPrefServiceInit,
+ base::Passed(&pref_service),
+ base::Passed(&callback)));
+ break;
+ case PrefService::INITIALIZATION_STATUS_SUCCESS:
+ case PrefService::INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE:
+ callback.Run(std::move(pref_service));
+ break;
+ case PrefService::INITIALIZATION_STATUS_ERROR:
+ callback.Run(nullptr);
+ break;
+ }
connector_ptr->reset();
}
@@ -99,10 +141,8 @@ void OnConnectError(
void ConnectToPrefService(
service_manager::Connector* connector,
scoped_refptr<PrefRegistry> pref_registry,
- std::vector<PrefValueStore::PrefStoreType> already_connected_types,
ConnectCallback callback,
base::StringPiece service_name) {
- already_connected_types.push_back(PrefValueStore::DEFAULT_STORE);
auto connector_ptr = make_scoped_refptr(
new RefCountedInterfacePtr<mojom::PrefStoreConnector>());
connector->BindInterface(service_name.as_string(), &connector_ptr->get());
@@ -110,9 +150,9 @@ void ConnectToPrefService(
&OnConnectError, connector_ptr, base::Passed(ConnectCallback{callback})));
auto serialized_pref_registry = SerializePrefRegistry(*pref_registry);
connector_ptr->get()->Connect(
- std::move(serialized_pref_registry), std::move(already_connected_types),
- base::Bind(&OnConnect, connector_ptr, base::Passed(&pref_registry),
- base::Passed(&callback)));
+ std::move(serialized_pref_registry),
+ base::BindOnce(&OnConnect, connector_ptr, std::move(pref_registry),
+ std::move(callback)));
}
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.h b/chromium/services/preferences/public/cpp/pref_service_factory.h
index e3cb3f344d3..9bae4322fda 100644
--- a/chromium/services/preferences/public/cpp/pref_service_factory.h
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.h
@@ -39,7 +39,6 @@ using ConnectCallback = base::Callback<void(std::unique_ptr<::PrefService>)>;
void ConnectToPrefService(
service_manager::Connector* connector,
scoped_refptr<PrefRegistry> pref_registry,
- std::vector<PrefValueStore::PrefStoreType> already_connected_types,
ConnectCallback callback,
base::StringPiece service_name = mojom::kServiceName);
diff --git a/chromium/services/preferences/public/cpp/pref_service_main.cc b/chromium/services/preferences/public/cpp/pref_service_main.cc
index b4c92c53060..c481b61b8a7 100644
--- a/chromium/services/preferences/public/cpp/pref_service_main.cc
+++ b/chromium/services/preferences/public/cpp/pref_service_main.cc
@@ -10,11 +10,21 @@
namespace prefs {
-std::unique_ptr<service_manager::Service> CreatePrefService(
- std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
- scoped_refptr<base::SequencedWorkerPool> worker_pool) {
- return base::MakeUnique<PrefStoreManagerImpl>(expected_pref_stores,
- std::move(worker_pool));
+std::pair<std::unique_ptr<service_manager::Service>, base::OnceClosure>
+CreatePrefService(PrefStore* managed_prefs,
+ PrefStore* supervised_user_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PersistentPrefStore* incognito_user_prefs_underlay,
+ PrefStore* recommended_prefs,
+ PrefRegistry* pref_registry) {
+ auto service = base::MakeUnique<PrefStoreManagerImpl>(
+ managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
+ user_prefs, incognito_user_prefs_underlay, recommended_prefs,
+ pref_registry);
+ auto quit_closure = service->ShutDownClosure();
+ return std::make_pair(std::move(service), std::move(quit_closure));
}
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_service_main.h b/chromium/services/preferences/public/cpp/pref_service_main.h
index 6b51efaf3c1..e0e50bff426 100644
--- a/chromium/services/preferences/public/cpp/pref_service_main.h
+++ b/chromium/services/preferences/public/cpp/pref_service_main.h
@@ -11,9 +11,8 @@
#include "base/memory/ref_counted.h"
#include "components/prefs/pref_value_store.h"
-namespace base {
-class SequencedWorkerPool;
-}
+class PersistentPrefStore;
+class PrefRegistry;
namespace service_manager {
class Service;
@@ -21,9 +20,16 @@ class Service;
namespace prefs {
-std::unique_ptr<service_manager::Service> CreatePrefService(
- std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
- scoped_refptr<base::SequencedWorkerPool> worker_pool);
+// Creates a PrefService and a closure that can be used to shut it down.
+std::pair<std::unique_ptr<service_manager::Service>, base::OnceClosure>
+CreatePrefService(PrefStore* managed_prefs,
+ PrefStore* supervised_user_prefs,
+ PrefStore* extension_prefs,
+ PrefStore* command_line_prefs,
+ PersistentPrefStore* user_prefs,
+ PersistentPrefStore* incognito_user_prefs_underlay,
+ PrefStore* recommended_prefs,
+ PrefRegistry* pref_registry);
} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_adapter.cc b/chromium/services/preferences/public/cpp/pref_store_adapter.cc
deleted file mode 100644
index 2cfe85a9167..00000000000
--- a/chromium/services/preferences/public/cpp/pref_store_adapter.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/preferences/public/cpp/pref_store_adapter.h"
-
-namespace prefs {
-
-PrefStoreAdapter::PrefStoreAdapter(scoped_refptr<PrefStore> pref_store,
- std::unique_ptr<PrefStoreImpl> impl)
- : pref_store_(std::move(pref_store)), impl_(std::move(impl)) {}
-
-void PrefStoreAdapter::AddObserver(PrefStore::Observer* observer) {
- pref_store_->AddObserver(observer);
-}
-
-void PrefStoreAdapter::RemoveObserver(PrefStore::Observer* observer) {
- pref_store_->RemoveObserver(observer);
-}
-
-bool PrefStoreAdapter::HasObservers() const {
- return pref_store_->HasObservers();
-}
-
-bool PrefStoreAdapter::IsInitializationComplete() const {
- return pref_store_->IsInitializationComplete();
-}
-
-bool PrefStoreAdapter::GetValue(const std::string& key,
- const base::Value** result) const {
- return pref_store_->GetValue(key, result);
-}
-
-std::unique_ptr<base::DictionaryValue> PrefStoreAdapter::GetValues() const {
- return pref_store_->GetValues();
-}
-
-PrefStoreAdapter::~PrefStoreAdapter() = default;
-
-} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_adapter.h b/chromium/services/preferences/public/cpp/pref_store_adapter.h
deleted file mode 100644
index c734606344e..00000000000
--- a/chromium/services/preferences/public/cpp/pref_store_adapter.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
-#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/values.h"
-#include "components/prefs/pref_store.h"
-#include "services/preferences/public/cpp/pref_store_impl.h"
-
-namespace prefs {
-
-// Ties the lifetime of a |PrefStoreImpl| to a |PrefStore|. Otherwise acts as a
-// |PrefStore|, forwarding all calls to the wrapped |PrefStore|.
-class PrefStoreAdapter : public PrefStore {
- public:
- PrefStoreAdapter(scoped_refptr<PrefStore> pref_store,
- std::unique_ptr<PrefStoreImpl> impl);
-
- // PrefStore:
- void AddObserver(PrefStore::Observer* observer) override;
- void RemoveObserver(PrefStore::Observer* observer) override;
- bool HasObservers() const override;
- bool IsInitializationComplete() const override;
- bool GetValue(const std::string& key,
- const base::Value** result) const override;
- std::unique_ptr<base::DictionaryValue> GetValues() const override;
-
- private:
- ~PrefStoreAdapter() override;
-
- scoped_refptr<PrefStore> pref_store_;
- std::unique_ptr<PrefStoreImpl> impl_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefStoreAdapter);
-};
-
-} // namespace prefs
-
-#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
diff --git a/chromium/services/preferences/public/cpp/pref_store_client.h b/chromium/services/preferences/public/cpp/pref_store_client.h
index b4d82451100..b7ca96e98c4 100644
--- a/chromium/services/preferences/public/cpp/pref_store_client.h
+++ b/chromium/services/preferences/public/cpp/pref_store_client.h
@@ -12,8 +12,6 @@
namespace prefs {
-// TODO(tibell): Make PrefObserverStore use PrefStoreClient as a base class.
-
// An implementation of PrefStore which uses prefs::mojom::PrefStore as
// the backing store of the preferences.
//
diff --git a/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc b/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc
index f78cf76e184..842e533da74 100644
--- a/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc
+++ b/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc
@@ -101,12 +101,19 @@ void PrefStoreClientMixin<BasePrefStore>::OnInitializationCompleted(
}
template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnPrefChangeAck() {}
+
+template <typename BasePrefStore>
void PrefStoreClientMixin<BasePrefStore>::OnPrefChanged(
const std::string& key,
mojom::PrefUpdateValuePtr update_value) {
DCHECK(cached_prefs_);
bool changed = false;
if (update_value->is_atomic_update()) {
+ if (ShouldSkipWrite(key, std::vector<std::string>(),
+ update_value->get_atomic_update().get())) {
+ return;
+ }
auto& value = update_value->get_atomic_update();
if (!value) { // Delete
if (cached_prefs_->RemovePath(key, nullptr))
@@ -129,9 +136,10 @@ void PrefStoreClientMixin<BasePrefStore>::OnPrefChanged(
changed = true;
for (auto& update : updates) {
// Clients shouldn't send empty paths.
- if (update->path.empty())
+ if (update->path.empty() ||
+ ShouldSkipWrite(key, update->path, update->value.get())) {
continue;
-
+ }
std::vector<base::StringPiece> full_path = base::SplitStringPiece(
key, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
full_path.insert(full_path.end(), update->path.begin(),
@@ -143,6 +151,14 @@ void PrefStoreClientMixin<BasePrefStore>::OnPrefChanged(
ReportPrefValueChanged(key);
}
+template <typename BasePrefStore>
+bool PrefStoreClientMixin<BasePrefStore>::ShouldSkipWrite(
+ const std::string& key,
+ const std::vector<std::string>& path,
+ const base::Value* new_value) {
+ return false;
+}
+
template class PrefStoreClientMixin<::PrefStore>;
template class PrefStoreClientMixin<::PersistentPrefStore>;
diff --git a/chromium/services/preferences/public/cpp/pref_store_client_mixin.h b/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
index 68286ec4bff..29cb6041f88 100644
--- a/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
+++ b/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
@@ -57,10 +57,17 @@ class PrefStoreClientMixin : public BasePrefStore,
// prefs::mojom::PreferenceObserver:
void OnPrefsChanged(std::vector<mojom::PrefUpdatePtr> updates) override;
void OnInitializationCompleted(bool succeeded) override;
+ void OnPrefChangeAck() override;
void OnPrefChanged(const std::string& key,
mojom::PrefUpdateValuePtr update_value);
+ // Should this client ignore a write received from the service? The default
+ // implementation never skips writes.
+ virtual bool ShouldSkipWrite(const std::string& key,
+ const std::vector<std::string>& path,
+ const base::Value* new_value);
+
// Cached preferences.
// If null, indicates that initialization failed.
std::unique_ptr<base::DictionaryValue> cached_prefs_;
diff --git a/chromium/services/preferences/public/cpp/tests/BUILD.gn b/chromium/services/preferences/public/cpp/tests/BUILD.gn
index 3f0a9c2c0e8..6e9cbc61e02 100644
--- a/chromium/services/preferences/public/cpp/tests/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/tests/BUILD.gn
@@ -7,7 +7,6 @@ source_set("tests") {
sources = [
"persistent_pref_store_client_unittest.cc",
"pref_store_client_unittest.cc",
- "pref_store_impl_unittest.cc",
]
deps = [
"//base",
diff --git a/chromium/services/preferences/public/cpp/tracked/configuration.h b/chromium/services/preferences/public/cpp/tracked/configuration.h
index bbb0ebff4ca..2b06c56f8dd 100644
--- a/chromium/services/preferences/public/cpp/tracked/configuration.h
+++ b/chromium/services/preferences/public/cpp/tracked/configuration.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
-#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
namespace prefs {
diff --git a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
index 5538c69301f..44f9fb87d1e 100644
--- a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
+++ b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
@@ -12,7 +12,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
class MockValidationDelegate;
diff --git a/chromium/services/preferences/public/interfaces/BUILD.gn b/chromium/services/preferences/public/interfaces/BUILD.gn
index 8bc3749fe60..58d8191fb9c 100644
--- a/chromium/services/preferences/public/interfaces/BUILD.gn
+++ b/chromium/services/preferences/public/interfaces/BUILD.gn
@@ -7,7 +7,6 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("interfaces") {
sources = [
"preferences.mojom",
- "preferences_configuration.mojom",
"tracked_preference_validation_delegate.mojom",
]
public_deps = [
diff --git a/chromium/services/preferences/public/interfaces/preferences.mojom b/chromium/services/preferences/public/interfaces/preferences.mojom
index eb4494567ae..02a8bf9c885 100644
--- a/chromium/services/preferences/public/interfaces/preferences.mojom
+++ b/chromium/services/preferences/public/interfaces/preferences.mojom
@@ -4,10 +4,13 @@
module prefs.mojom;
+import "mojo/common/file_path.mojom";
+import "mojo/common/string16.mojom";
import "mojo/common/values.mojom";
-import "services/preferences/public/interfaces/preferences_configuration.mojom";
+import "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom";
const string kServiceName = "preferences";
+const string kLocalStateServiceName = "local_state";
const string kForwarderServiceName = "preferences_forwarder";
// The know pref store types.
@@ -30,6 +33,13 @@ interface PrefStoreObserver {
// The PrefStore has been initialized (asynchronously).
OnInitializationCompleted(bool succeeded);
+
+ // A preference write by this client has been applied. If this
+ // PrefStoreObserver is associated with a PersistentPrefStore, one
+ // OnPrefChangeAck() message is sent in response to each SetValues() message.
+ // This exists to ensure acks are ordered with respect to OnPrefsChanged
+ // messages.
+ OnPrefChangeAck();
};
// Captures the connections to a PrefStore by supplying the initial state of the
@@ -68,34 +78,21 @@ struct PersistentPrefStoreConnection {
bool read_only;
};
-// Manages actual read of preference data. Accepts observers who subscribe to
-// preferences, notifying them of changes.
-interface PrefStore {
- // Add an observer of changes to prefs contained in |prefs_to_observe|. This
- // current values of all prefs will not be communicated through a call to
- // |observer| but instead be returned in |initial_prefs|.
- AddObserver(array<string> prefs_to_observe) => (
- PrefStoreConnection connection);
-};
-
-// Manages a registry of all pref stores. Registered pref stores can be
-// connected to through the |PrefStoreConnector| interface.
-interface PrefStoreRegistry {
- // Register a pref store.
- Register(PrefStoreType type, PrefStore pref_store);
-};
-
// Allows connections to pref stores registered with |PrefStoreRegistry|.
interface PrefStoreConnector {
// Connect to all registered pref stores, retrieving the current values of all
// prefs in each store and an |observer| interfaces through which updates can
- // be received. The client asserts that it is already connected to the
- // |already_connected_types| pref stores through some other means, so the
- // Connect call will not connect to those.
- [Sync]
- Connect(PrefRegistry pref_registry,
- array<PrefStoreType> already_connected_types) =>
+ // be received.
+ //
+ // The returned |connection| is the connection to the main writable user pref
+ // store.
+ //
+ // Calls to |Connect| before |Init| are allowed and will cause the calls to
+ // queue and connect once |Init| has been called.
+ Connect(PrefRegistry pref_registry) =>
(PersistentPrefStoreConnection connection,
+ PersistentPrefStoreConnection? underlay,
+ array<PrefRegistration> remote_defaults,
map<PrefStoreType, PrefStoreConnection> connections);
};
@@ -130,18 +127,36 @@ interface PersistentPrefStore {
// Sets the values for prefs.
SetValues(array<PrefUpdate> updates);
+ // Requests that the pref service transmits its value for a pref (or sub-pref
+ // if |sub_pref_path| is non-empty). The value will be transmitted over the
+ // corresponding PrefStoreObserver interface previous returned by
+ // PrefStoreConnector.Connect().
+ RequestValue(string key, array<string> sub_pref_path);
+
// These mirror the C++ PersistentPrefStore methods.
- CommitPendingWrite();
+ CommitPendingWrite() => ();
SchedulePendingLossyWrites();
ClearMutableValues();
};
// A registry of all prefs registered by a single client.
struct PrefRegistry {
- array<string> registrations;
+ // A list of pref keys that are private to this client. This client claims
+ // exclusive access to these prefs.
+ array<string> private_registrations;
+
+ // A list of pref keys that are public, but owned by another client.
+ array<string> foreign_registrations;
+
+ // A list of prefs that are publicly owned by this client. Each registration
+ // contains the key, the default value and flags. These are shared with
+ // clients that list the same pref in |foreign_registrations|.
+ array<PrefRegistration> public_registrations;
};
struct PrefRegistration {
+ string key;
+
mojo.common.mojom.Value default_value;
// A bitfield of flags. Flag values are defined in
@@ -150,8 +165,49 @@ struct PrefRegistration {
uint32 flags;
};
-interface PrefServiceControl {
- // Initializes the pref service. This must be called before the service can
- // be used.
- Init(PersistentPrefStoreConfiguration configuration);
+// ---------------------------------------------------------------------
+// Service Configuration
+
+// These parameters are passed to prefs::CreateTrackedPersistentPrefStore() in
+// services/preferences/persistent_pref_store_factory.cc.
+struct TrackedPersistentPrefStoreConfiguration {
+ mojo.common.mojom.FilePath unprotected_pref_filename;
+ mojo.common.mojom.FilePath protected_pref_filename;
+ array<TrackedPreferenceMetadata> tracking_configuration;
+ uint64 reporting_ids_count;
+ string seed;
+ string legacy_device_id;
+ string registry_seed;
+ mojo.common.mojom.String16 registry_path;
+ TrackedPreferenceValidationDelegate? validation_delegate;
+ ResetOnLoadObserver? reset_on_load_observer;
+};
+
+struct TrackedPreferenceMetadata {
+ enum EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD };
+
+ enum PrefTrackingStrategy {
+ // Atomic preferences are tracked as a whole.
+ ATOMIC,
+ // Split preferences are dictionaries for which each top-level entry is
+ // tracked independently. Note: preferences using this strategy must be kept
+ // in sync with TrackedSplitPreferences in histograms.xml.
+ SPLIT,
+ };
+
+ enum ValueType {
+ IMPERSONAL,
+ // The preference value may contain personal information.
+ PERSONAL,
+ };
+
+ uint64 reporting_id;
+ string name;
+ EnforcementLevel enforcement_level;
+ PrefTrackingStrategy strategy;
+ ValueType value_type;
+};
+
+interface ResetOnLoadObserver {
+ OnResetOnLoad();
};
diff --git a/chromium/services/preferences/public/interfaces/preferences_configuration.mojom b/chromium/services/preferences/public/interfaces/preferences_configuration.mojom
deleted file mode 100644
index 76f7785ae06..00000000000
--- a/chromium/services/preferences/public/interfaces/preferences_configuration.mojom
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module prefs.mojom;
-
-import "mojo/common/file_path.mojom";
-import "mojo/common/string16.mojom";
-import "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom";
-
-union PersistentPrefStoreConfiguration {
- SimplePersistentPrefStoreConfiguration simple_configuration;
- TrackedPersistentPrefStoreConfiguration tracked_configuration;
-};
-
-struct SimplePersistentPrefStoreConfiguration {
- mojo.common.mojom.FilePath pref_filename;
-};
-
-// These parameters are passed to prefs::CreateTrackedPersistentPrefStore() in
-// services/preferences/persistent_pref_store_factory.cc.
-struct TrackedPersistentPrefStoreConfiguration {
- mojo.common.mojom.FilePath unprotected_pref_filename;
- mojo.common.mojom.FilePath protected_pref_filename;
- array<TrackedPreferenceMetadata> tracking_configuration;
- uint64 reporting_ids_count;
- string seed;
- string legacy_device_id;
- string registry_seed;
- mojo.common.mojom.String16 registry_path;
- TrackedPreferenceValidationDelegate? validation_delegate;
- ResetOnLoadObserver? reset_on_load_observer;
-};
-
-struct TrackedPreferenceMetadata {
- enum EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD };
-
- enum PrefTrackingStrategy {
- // Atomic preferences are tracked as a whole.
- ATOMIC,
- // Split preferences are dictionaries for which each top-level entry is
- // tracked independently. Note: preferences using this strategy must be kept
- // in sync with TrackedSplitPreferences in histograms.xml.
- SPLIT,
- };
-
- enum ValueType {
- IMPERSONAL,
- // The preference value may contain personal information.
- PERSONAL,
- };
-
- uint64 reporting_id;
- string name;
- EnforcementLevel enforcement_level;
- PrefTrackingStrategy strategy;
- ValueType value_type;
-};
-
-interface ResetOnLoadObserver {
- OnResetOnLoad();
-};
diff --git a/chromium/services/preferences/scoped_pref_connection_builder.cc b/chromium/services/preferences/scoped_pref_connection_builder.cc
index 8e6af170064..5ad903c52e2 100644
--- a/chromium/services/preferences/scoped_pref_connection_builder.cc
+++ b/chromium/services/preferences/scoped_pref_connection_builder.cc
@@ -5,37 +5,31 @@
#include "services/preferences/scoped_pref_connection_builder.h"
#include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/pref_store_impl.h"
namespace prefs {
ScopedPrefConnectionBuilder::ScopedPrefConnectionBuilder(
std::vector<std::string> observed_prefs,
- std::set<PrefValueStore::PrefStoreType> required_types,
mojom::PrefStoreConnector::ConnectCallback callback)
: callback_(std::move(callback)),
- observed_prefs_(std::move(observed_prefs)),
- required_types_(std::move(required_types)) {}
+ observed_prefs_(std::move(observed_prefs)) {}
-std::set<PrefValueStore::PrefStoreType>
-ScopedPrefConnectionBuilder::ProvidePrefStoreConnections(
+void ScopedPrefConnectionBuilder::ProvidePrefStoreConnections(
const std::unordered_map<PrefValueStore::PrefStoreType,
- mojom::PrefStorePtr>& pref_stores) {
+ std::unique_ptr<PrefStoreImpl>>& pref_stores) {
for (const auto& pref_store : pref_stores) {
- auto it = required_types_.find(pref_store.first);
- if (it != required_types_.end()) {
- ProvidePrefStoreConnection(pref_store.first, pref_store.second.get());
- required_types_.erase(it);
- }
+ ProvidePrefStoreConnection(pref_store.first, pref_store.second.get());
}
- return std::move(required_types_);
}
void ScopedPrefConnectionBuilder::ProvidePrefStoreConnection(
PrefValueStore::PrefStoreType type,
- mojom::PrefStore* pref_store) {
- pref_store->AddObserver(
- observed_prefs_,
- base::Bind(&ScopedPrefConnectionBuilder::OnConnect, this, type));
+ PrefStoreImpl* pref_store) {
+ bool inserted =
+ connections_.emplace(type, pref_store->AddObserver(observed_prefs_))
+ .second;
+ DCHECK(inserted);
}
void ScopedPrefConnectionBuilder::ProvidePersistentPrefStore(
@@ -46,16 +40,22 @@ void ScopedPrefConnectionBuilder::ProvidePersistentPrefStore(
observed_prefs_.end()));
}
-ScopedPrefConnectionBuilder::~ScopedPrefConnectionBuilder() {
- std::move(callback_).Run(std::move(persistent_pref_store_connection_),
- std::move(connections_));
+void ScopedPrefConnectionBuilder::ProvideIncognitoPersistentPrefStoreUnderlay(
+ PersistentPrefStoreImpl* persistent_pref_store) {
+ incognito_connection_ = persistent_pref_store->CreateConnection(
+ PersistentPrefStoreImpl::ObservedPrefs(observed_prefs_.begin(),
+ observed_prefs_.end()));
}
-void ScopedPrefConnectionBuilder::OnConnect(
- PrefValueStore::PrefStoreType type,
- mojom::PrefStoreConnectionPtr connection_ptr) {
- bool inserted = connections_.emplace(type, std::move(connection_ptr)).second;
- DCHECK(inserted);
+void ScopedPrefConnectionBuilder::ProvideDefaults(
+ std::vector<mojom::PrefRegistrationPtr> defaults) {
+ defaults_ = std::move(defaults);
+}
+
+ScopedPrefConnectionBuilder::~ScopedPrefConnectionBuilder() {
+ std::move(callback_).Run(std::move(persistent_pref_store_connection_),
+ std::move(incognito_connection_),
+ std::move(defaults_), std::move(connections_));
}
} // namespace prefs
diff --git a/chromium/services/preferences/scoped_pref_connection_builder.h b/chromium/services/preferences/scoped_pref_connection_builder.h
index c73e97e88c9..270b31bbaee 100644
--- a/chromium/services/preferences/scoped_pref_connection_builder.h
+++ b/chromium/services/preferences/scoped_pref_connection_builder.h
@@ -16,47 +16,47 @@
namespace prefs {
class PersistentPrefStoreImpl;
+class PrefStoreImpl;
// A builder for connections to pref stores. When all references are released,
// the connection is created.
class ScopedPrefConnectionBuilder
: public base::RefCounted<ScopedPrefConnectionBuilder> {
public:
- // |required_types| lists all the |Provide*| calls the client of this object
- // is expected to make. Once all these |Provide*| calls have been made, the
- // |callback| will be invoked.
ScopedPrefConnectionBuilder(
std::vector<std::string> observed_prefs,
- std::set<PrefValueStore::PrefStoreType> required_types,
mojom::PrefStoreConnector::ConnectCallback callback);
- std::set<PrefValueStore::PrefStoreType> ProvidePrefStoreConnections(
+ void ProvidePrefStoreConnections(
const std::unordered_map<PrefValueStore::PrefStoreType,
- mojom::PrefStorePtr>& pref_stores);
+ std::unique_ptr<PrefStoreImpl>>& pref_stores);
void ProvidePrefStoreConnection(PrefValueStore::PrefStoreType type,
- mojom::PrefStore* ptr);
+ PrefStoreImpl* ptr);
void ProvidePersistentPrefStore(
PersistentPrefStoreImpl* persistent_pref_store);
+ void ProvideIncognitoPersistentPrefStoreUnderlay(
+ PersistentPrefStoreImpl* persistent_pref_store);
+
+ void ProvideDefaults(std::vector<mojom::PrefRegistrationPtr> defaults);
+
private:
friend class base::RefCounted<ScopedPrefConnectionBuilder>;
~ScopedPrefConnectionBuilder();
- void OnConnect(PrefValueStore::PrefStoreType type,
- mojom::PrefStoreConnectionPtr connection_ptr);
-
mojom::PrefStoreConnector::ConnectCallback callback_;
std::vector<std::string> observed_prefs_;
- std::set<PrefValueStore::PrefStoreType> required_types_;
-
std::unordered_map<PrefValueStore::PrefStoreType,
mojom::PrefStoreConnectionPtr>
connections_;
+ std::vector<mojom::PrefRegistrationPtr> defaults_;
+
mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection_;
+ mojom::PersistentPrefStoreConnectionPtr incognito_connection_;
DISALLOW_COPY_AND_ASSIGN(ScopedPrefConnectionBuilder);
};
diff --git a/chromium/services/preferences/shared_pref_registry.cc b/chromium/services/preferences/shared_pref_registry.cc
new file mode 100644
index 00000000000..4889f581f2f
--- /dev/null
+++ b/chromium/services/preferences/shared_pref_registry.cc
@@ -0,0 +1,190 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/preferences/shared_pref_registry.h"
+
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_store.h"
+#include "services/preferences/scoped_pref_connection_builder.h"
+#include "services/service_manager/public/cpp/identity.h"
+
+namespace prefs {
+
+class SharedPrefRegistry::PendingConnection {
+ public:
+ PendingConnection(SharedPrefRegistry* owner,
+ scoped_refptr<ScopedPrefConnectionBuilder> connection,
+ std::vector<std::string> foreign_prefs,
+ std::set<std::string> pending_prefs)
+ : owner_(owner),
+ connection_(std::move(connection)),
+ foreign_prefs_(std::move(foreign_prefs)),
+ pending_prefs_(std::move(pending_prefs)) {}
+
+ PendingConnection(PendingConnection&& other) = default;
+ PendingConnection& operator=(PendingConnection&& other) = default;
+
+ bool NewPublicPrefsRegistered(const std::vector<std::string>& keys) {
+ for (auto& key : keys) {
+ pending_prefs_.erase(key);
+ }
+ if (pending_prefs_.empty()) {
+ owner_->ProvideDefaultPrefs(connection_.get(), std::move(foreign_prefs_));
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ SharedPrefRegistry* owner_;
+ scoped_refptr<ScopedPrefConnectionBuilder> connection_;
+ std::vector<std::string> foreign_prefs_;
+ std::set<std::string> pending_prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingConnection);
+};
+
+SharedPrefRegistry::SharedPrefRegistry(scoped_refptr<PrefRegistry> registry)
+ : registry_(std::move(registry)) {
+ for (const auto& pref : *registry_) {
+#if DCHECK_IS_ON()
+ all_registered_pref_keys_.insert(pref.first);
+#endif
+ if (registry_->GetRegistrationFlags(pref.first) & PrefRegistry::PUBLIC)
+ public_pref_keys_.insert(std::move(pref.first));
+ }
+}
+
+SharedPrefRegistry::~SharedPrefRegistry() = default;
+
+scoped_refptr<ScopedPrefConnectionBuilder>
+SharedPrefRegistry::CreateConnectionBuilder(
+ mojom::PrefRegistryPtr pref_registry,
+ const service_manager::Identity& identity,
+ mojom::PrefStoreConnector::ConnectCallback callback) {
+ bool is_initial_connection = connected_services_.insert(identity).second;
+#if DCHECK_IS_ON()
+ if (is_initial_connection) {
+ for (const auto& key : pref_registry->private_registrations) {
+ bool inserted = all_registered_pref_keys_.insert(key).second;
+ DCHECK(inserted) << "Multiple services claimed ownership of pref \""
+ << key << "\"";
+ }
+ }
+#endif
+
+ std::vector<std::string>& observed_prefs =
+ pref_registry->private_registrations;
+ observed_prefs.reserve(observed_prefs.size() +
+ pref_registry->foreign_registrations.size() +
+ pref_registry->public_registrations.size());
+
+ std::set<std::string> remaining_foreign_registrations =
+ GetPendingForeignPrefs(pref_registry->foreign_registrations,
+ &observed_prefs);
+
+ ProcessPublicPrefs(std::move(pref_registry->public_registrations),
+ is_initial_connection, &observed_prefs);
+#if DCHECK_IS_ON()
+ if (is_initial_connection) {
+ per_service_registered_pref_keys_.emplace(
+ identity,
+ std::set<std::string>(observed_prefs.begin(), observed_prefs.end()));
+ } else {
+ DCHECK(per_service_registered_pref_keys_[identity] ==
+ std::set<std::string>(observed_prefs.begin(), observed_prefs.end()));
+ }
+#endif
+
+ auto connection_builder = base::MakeRefCounted<ScopedPrefConnectionBuilder>(
+ std::move(observed_prefs), std::move(callback));
+ if (remaining_foreign_registrations.empty()) {
+ ProvideDefaultPrefs(connection_builder.get(),
+ pref_registry->foreign_registrations);
+ } else {
+ pending_connections_.emplace_back(
+ this, connection_builder, pref_registry->foreign_registrations,
+ std::move(remaining_foreign_registrations));
+ }
+ return connection_builder;
+}
+
+std::set<std::string> SharedPrefRegistry::GetPendingForeignPrefs(
+ std::vector<std::string> foreign_prefs,
+ std::vector<std::string>* observed_prefs) const {
+ std::set<std::string> pending_foreign_prefs;
+ if (foreign_prefs.empty())
+ return pending_foreign_prefs;
+
+ observed_prefs->insert(observed_prefs->end(), foreign_prefs.begin(),
+ foreign_prefs.end());
+ std::sort(foreign_prefs.begin(), foreign_prefs.end());
+ std::set_difference(
+ std::make_move_iterator(foreign_prefs.begin()),
+ std::make_move_iterator(foreign_prefs.end()), public_pref_keys_.begin(),
+ public_pref_keys_.end(),
+ std::inserter(pending_foreign_prefs, pending_foreign_prefs.end()));
+ return pending_foreign_prefs;
+}
+
+void SharedPrefRegistry::ProcessPublicPrefs(
+ std::vector<mojom::PrefRegistrationPtr> public_pref_registrations,
+ bool is_initial_connection,
+ std::vector<std::string>* observed_prefs) {
+ if (public_pref_registrations.empty())
+ return;
+
+ if (is_initial_connection) {
+ std::vector<std::string> new_public_prefs;
+ for (auto& registration : public_pref_registrations) {
+ auto& key = registration->key;
+ auto& default_value = registration->default_value;
+#if DCHECK_IS_ON()
+ bool inserted = all_registered_pref_keys_.insert(key).second;
+ DCHECK(inserted) << "Multiple services claimed ownership of pref \""
+ << key << "\"";
+#endif
+ registry_->RegisterForeignPref(key);
+ registry_->SetDefaultForeignPrefValue(key, std::move(default_value),
+ registration->flags);
+
+ observed_prefs->push_back(key);
+ new_public_prefs.push_back(key);
+ public_pref_keys_.insert(std::move(key));
+ }
+ pending_connections_.erase(
+ std::remove_if(pending_connections_.begin(), pending_connections_.end(),
+ [&](PendingConnection& connection) {
+ return connection.NewPublicPrefsRegistered(
+ new_public_prefs);
+ }),
+ pending_connections_.end());
+ } else {
+ for (auto& registration : public_pref_registrations) {
+ observed_prefs->push_back(registration->key);
+#if DCHECK_IS_ON()
+ const base::Value* existing_default_value = nullptr;
+ DCHECK(registry_->defaults()->GetValue(registration->key,
+ &existing_default_value));
+ DCHECK_EQ(*existing_default_value, *registration->default_value);
+#endif
+ }
+ }
+}
+
+void SharedPrefRegistry::ProvideDefaultPrefs(
+ ScopedPrefConnectionBuilder* connection,
+ std::vector<std::string> foreign_prefs) {
+ std::vector<mojom::PrefRegistrationPtr> defaults;
+ for (const auto& key : foreign_prefs) {
+ const base::Value* value = nullptr;
+ registry_->defaults()->GetValue(key, &value);
+ defaults.emplace_back(base::in_place, key, value->CreateDeepCopy(),
+ registry_->GetRegistrationFlags(key));
+ }
+
+ connection->ProvideDefaults(std::move(defaults));
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/shared_pref_registry.h b/chromium/services/preferences/shared_pref_registry.h
new file mode 100644
index 00000000000..397fa6d4da7
--- /dev/null
+++ b/chromium/services/preferences/shared_pref_registry.h
@@ -0,0 +1,80 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_SHARED_PREF_REGISTRY_H_
+#define SERVICES_PREFERENCES_SHARED_PREF_REGISTRY_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+
+class PrefRegistry;
+
+namespace service_manager {
+class Identity;
+}
+
+namespace prefs {
+class ScopedPrefConnectionBuilder;
+
+// A registry of default pref values for public prefs. It records public default
+// pref values from connections and provides public default pref values to
+// connections that require them.
+class SharedPrefRegistry {
+ public:
+ explicit SharedPrefRegistry(scoped_refptr<PrefRegistry> registry);
+ ~SharedPrefRegistry();
+
+ scoped_refptr<ScopedPrefConnectionBuilder> CreateConnectionBuilder(
+ mojom::PrefRegistryPtr pref_registry,
+ const service_manager::Identity& identity,
+ mojom::PrefStoreConnector::ConnectCallback callback);
+
+ private:
+ class PendingConnection;
+
+ std::set<std::string> GetPendingForeignPrefs(
+ std::vector<std::string> foreign_prefs,
+ std::vector<std::string>* observed_prefs) const;
+
+ void ProcessPublicPrefs(
+ std::vector<mojom::PrefRegistrationPtr> public_pref_registrations,
+ bool enforce_single_owner_check,
+ std::vector<std::string>* observed_prefs);
+
+ void ProvideDefaultPrefs(ScopedPrefConnectionBuilder* connection,
+ std::vector<std::string> foreign_prefs);
+
+ scoped_refptr<PrefRegistry> registry_;
+
+ std::set<std::string> public_pref_keys_;
+
+ std::set<service_manager::Identity> connected_services_;
+
+ std::vector<PendingConnection> pending_connections_;
+
+#if DCHECK_IS_ON()
+ // The set of all registered pref keys. This enforces that only one service
+ // claims ownership over any pref. This is relatively expensive so skip
+ // unless dchecks are enabled.
+ std::set<std::string> all_registered_pref_keys_;
+
+ // Maps from service identity to the set of pref keys registered by that
+ // service. This enforces that each service registers the same keys for each
+ // connect. This is relatively expensive so skip unless dchecks are enabled.
+ std::map<service_manager::Identity, std::set<std::string>>
+ per_service_registered_pref_keys_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(SharedPrefRegistry);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_SHARED_PREF_REGISTRY_H_
diff --git a/chromium/services/preferences/tracked/BUILD.gn b/chromium/services/preferences/tracked/BUILD.gn
index 16be8a2d696..00aca10ad58 100644
--- a/chromium/services/preferences/tracked/BUILD.gn
+++ b/chromium/services/preferences/tracked/BUILD.gn
@@ -25,6 +25,7 @@ source_set("tracked") {
"registry_hash_store_contents_win.h",
"segregated_pref_store.cc",
"segregated_pref_store.h",
+ "temp_scoped_dir_cleaner.h",
"tracked_atomic_preference.cc",
"tracked_atomic_preference.h",
"tracked_persistent_pref_store_factory.cc",
diff --git a/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc b/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc
index 3cef69b05a1..2901657e7c6 100644
--- a/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc
+++ b/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/persistent_pref_store.h"
@@ -94,7 +95,7 @@ void DictionaryHashStoreContents::SetSplitMac(const std::string& path,
void DictionaryHashStoreContents::ImportEntry(const std::string& path,
const base::Value* in_value) {
base::DictionaryValue* macs_dict = GetMutableContents(true);
- macs_dict->Set(path, in_value->DeepCopy());
+ macs_dict->Set(path, base::MakeUnique<base::Value>(*in_value));
}
bool DictionaryHashStoreContents::RemoveEntry(const std::string& path) {
@@ -126,8 +127,8 @@ base::DictionaryValue* DictionaryHashStoreContents::GetMutableContents(
base::DictionaryValue* macs_dict = NULL;
storage_->GetDictionary(kPreferenceMACs, &macs_dict);
if (!macs_dict && create_if_null) {
- macs_dict = new base::DictionaryValue;
- storage_->Set(kPreferenceMACs, macs_dict);
+ macs_dict = storage_->SetDictionary(
+ kPreferenceMACs, base::MakeUnique<base::DictionaryValue>());
}
return macs_dict;
}
diff --git a/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc b/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc
index df3746a09e0..0dc9765102d 100644
--- a/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc
+++ b/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -18,7 +19,8 @@ TEST(PrefHashCalculatorTest, TestCurrentAlgorithm) {
base::Value string_value_2("string value 2");
base::DictionaryValue dictionary_value_1;
dictionary_value_1.SetInteger("int value", 1);
- dictionary_value_1.Set("nested empty map", new base::DictionaryValue);
+ dictionary_value_1.Set("nested empty map",
+ base::MakeUnique<base::DictionaryValue>());
base::DictionaryValue dictionary_value_1_equivalent;
dictionary_value_1_equivalent.SetInteger("int value", 1);
base::DictionaryValue dictionary_value_2;
@@ -77,34 +79,33 @@ TEST(PrefHashCalculatorTest, CatchHashChanges) {
static const char kDeviceId[] = "test_device_id1";
auto null_value = base::MakeUnique<base::Value>();
- std::unique_ptr<base::Value> bool_value(new base::Value(false));
- std::unique_ptr<base::Value> int_value(new base::Value(1234567890));
- std::unique_ptr<base::Value> double_value(new base::Value(123.0987654321));
- std::unique_ptr<base::Value> string_value(
- new base::Value("testing with special chars:\n<>{}:^^@#$\\/"));
+ auto bool_value = base::MakeUnique<base::Value>(false);
+ auto int_value = base::MakeUnique<base::Value>(1234567890);
+ auto double_value = base::MakeUnique<base::Value>(123.0987654321);
+ auto string_value = base::MakeUnique<base::Value>(
+ "testing with special chars:\n<>{}:^^@#$\\/");
// For legacy reasons, we have to support pruning of empty lists/dictionaries
// and nested empty ists/dicts in the hash generation algorithm.
- std::unique_ptr<base::DictionaryValue> nested_empty_dict(
- new base::DictionaryValue);
- nested_empty_dict->Set("a", new base::DictionaryValue);
- nested_empty_dict->Set("b", new base::ListValue);
- std::unique_ptr<base::ListValue> nested_empty_list(new base::ListValue);
+ auto nested_empty_dict = base::MakeUnique<base::DictionaryValue>();
+ nested_empty_dict->Set("a", base::MakeUnique<base::DictionaryValue>());
+ nested_empty_dict->Set("b", base::MakeUnique<base::ListValue>());
+ auto nested_empty_list = base::MakeUnique<base::ListValue>();
nested_empty_list->Append(base::MakeUnique<base::DictionaryValue>());
nested_empty_list->Append(base::MakeUnique<base::ListValue>());
- nested_empty_list->Append(nested_empty_dict->CreateDeepCopy());
+ nested_empty_list->Append(base::MakeUnique<base::Value>(*nested_empty_dict));
// A dictionary with an empty dictionary, an empty list, and nested empty
// dictionaries/lists in it.
- std::unique_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue);
- dict_value->Set("a", new base::Value("foo"));
- dict_value->Set("d", new base::ListValue);
- dict_value->Set("b", new base::DictionaryValue);
- dict_value->Set("c", new base::Value("baz"));
- dict_value->Set("e", nested_empty_dict.release());
- dict_value->Set("f", nested_empty_list.release());
-
- std::unique_ptr<base::ListValue> list_value(new base::ListValue);
+ auto dict_value = base::MakeUnique<base::DictionaryValue>();
+ dict_value->SetString("a", "foo");
+ dict_value->Set("d", base::MakeUnique<base::ListValue>());
+ dict_value->Set("b", base::MakeUnique<base::DictionaryValue>());
+ dict_value->SetString("c", "baz");
+ dict_value->Set("e", std::move(nested_empty_dict));
+ dict_value->Set("f", std::move(nested_empty_list));
+
+ auto list_value = base::MakeUnique<base::ListValue>();
list_value->AppendBoolean(true);
list_value->AppendInteger(100);
list_value->AppendDouble(1.0);
@@ -166,13 +167,13 @@ TEST(PrefHashCalculatorTest, CatchHashChanges) {
// Also test every value type together in the same dictionary.
base::DictionaryValue everything;
- everything.Set("null", null_value.release());
- everything.Set("bool", bool_value.release());
- everything.Set("int", int_value.release());
- everything.Set("double", double_value.release());
- everything.Set("string", string_value.release());
- everything.Set("list", list_value.release());
- everything.Set("dict", dict_value.release());
+ everything.Set("null", std::move(null_value));
+ everything.Set("bool", std::move(bool_value));
+ everything.Set("int", std::move(int_value));
+ everything.Set("double", std::move(double_value));
+ everything.Set("string", std::move(string_value));
+ everything.Set("list", std::move(list_value));
+ everything.Set("dict", std::move(dict_value));
static const char kExpectedEverythingValue[] =
"B97D09BE7005693574DCBDD03D8D9E44FB51F4008B73FB56A49A9FA671A1999B";
EXPECT_EQ(PrefHashCalculator::VALID,
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.cc b/chromium/services/preferences/tracked/pref_hash_filter.cc
index 29d6b9ab830..a0b94dfff32 100644
--- a/chromium/services/preferences/tracked/pref_hash_filter.cc
+++ b/chromium/services/preferences/tracked/pref_hash_filter.cc
@@ -243,9 +243,9 @@ void PrefHashFilter::FinalizeFilterOnLoad(
}
if (did_reset) {
- pref_store_contents->Set(user_prefs::kPreferenceResetTime,
- new base::Value(base::Int64ToString(
- base::Time::Now().ToInternalValue())));
+ pref_store_contents->SetString(
+ user_prefs::kPreferenceResetTime,
+ base::Int64ToString(base::Time::Now().ToInternalValue()));
FilterUpdate(user_prefs::kPreferenceResetTime);
if (reset_on_load_observer_)
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.h b/chromium/services/preferences/tracked/pref_hash_filter.h
index 4c3cdaa4996..6467eb10dba 100644
--- a/chromium/services/preferences/tracked/pref_hash_filter.h
+++ b/chromium/services/preferences/tracked/pref_hash_filter.h
@@ -18,7 +18,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
#include "services/preferences/tracked/hash_store_contents.h"
#include "services/preferences/tracked/interceptable_pref_filter.h"
#include "services/preferences/tracked/tracked_preference.h"
diff --git a/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc b/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc
index 50b7ee29427..b1e0258ca85 100644
--- a/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc
+++ b/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc
@@ -583,13 +583,15 @@ class PrefHashFilterTest : public testing::TestWithParam<EnforcementLevel>,
temp_mock_external_validation_pref_hash_store.get();
mock_external_validation_hash_store_contents_ =
temp_mock_external_validation_hash_store_contents.get();
+ prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer;
+ reset_on_load_observer_bindings_.AddBinding(
+ this, mojo::MakeRequest(&reset_on_load_observer));
pref_hash_filter_.reset(new PrefHashFilter(
std::move(temp_mock_pref_hash_store),
PrefHashFilter::StoreContentsPair(
std::move(temp_mock_external_validation_pref_hash_store),
std::move(temp_mock_external_validation_hash_store_contents)),
- std::move(configuration),
- reset_on_load_observer_bindings_.CreateInterfacePtrAndBind(this),
+ std::move(configuration), std::move(reset_on_load_observer),
&mock_validation_delegate_, arraysize(kTestTrackedPrefs), true));
}
@@ -682,9 +684,7 @@ TEST_P(PrefHashFilterTest, StampSuperMACAltersStore) {
TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
base::DictionaryValue root_dict;
- // Ownership of |string_value| is transfered to |root_dict|.
- base::Value* string_value = new base::Value("string value");
- root_dict.Set(kAtomicPref, string_value);
+ base::Value* string_value = root_dict.SetString(kAtomicPref, "string value");
// No path should be stored on FilterUpdate.
pref_hash_filter_->FilterUpdate(kAtomicPref);
@@ -740,11 +740,10 @@ TEST_P(PrefHashFilterTest, ReportSuperMacValidity) {
TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
base::DictionaryValue root_dict;
- // Ownership of |dict_value| is transfered to |root_dict|.
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ base::DictionaryValue* dict_value = root_dict.SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
- root_dict.Set(kSplitPref, dict_value);
// No path should be stored on FilterUpdate.
pref_hash_filter_->FilterUpdate(kSplitPref);
@@ -764,7 +763,7 @@ TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
base::DictionaryValue root_dict;
- root_dict.Set("untracked", new base::Value("some value"));
+ root_dict.SetString("untracked", "some value");
pref_hash_filter_->FilterUpdate("untracked");
// No paths should be stored on FilterUpdate.
@@ -781,18 +780,13 @@ TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::Value* int_value3 = new base::Value(3);
- base::Value* int_value4 = new base::Value(4);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->Set("a", new base::Value(true));
- root_dict.Set(kAtomicPref, int_value1);
- root_dict.Set(kAtomicPref2, int_value2);
- root_dict.Set(kAtomicPref3, int_value3);
- root_dict.Set("untracked", int_value4);
- root_dict.Set(kSplitPref, dict_value);
+ base::Value* int_value1 = root_dict.SetInteger(kAtomicPref, 1);
+ root_dict.SetInteger(kAtomicPref2, 2);
+ root_dict.SetInteger(kAtomicPref3, 3);
+ root_dict.SetInteger("untracked", 4);
+ base::DictionaryValue* dict_value = root_dict.SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
+ dict_value->SetBoolean("a", true);
// Only update kAtomicPref, kAtomicPref3, and kSplitPref.
pref_hash_filter_->FilterUpdate(kAtomicPref);
@@ -801,8 +795,7 @@ TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
// Update kAtomicPref3 again, nothing should be stored still.
- base::Value* int_value5 = new base::Value(5);
- root_dict.Set(kAtomicPref3, int_value5);
+ base::Value* int_value5 = root_dict.SetInteger(kAtomicPref3, 5);
ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
// On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
@@ -870,14 +863,13 @@ TEST_P(PrefHashFilterTest, UnknownNullValue) {
}
TEST_P(PrefHashFilterTest, InitialValueUnknown) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::Value* string_value = new base::Value("string value");
- pref_store_contents_->Set(kAtomicPref, string_value);
+ base::Value* string_value =
+ pref_store_contents_->SetString(kAtomicPref, "string value");
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -936,14 +928,13 @@ TEST_P(PrefHashFilterTest, InitialValueUnknown) {
}
TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* string_value = new base::Value("test");
- pref_store_contents_->Set(kAtomicPref, string_value);
+ base::Value* string_value =
+ pref_store_contents_->SetString(kAtomicPref, "test");
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ auto* dict_value = pref_store_contents_->SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -986,16 +977,14 @@ TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
}
TEST_P(PrefHashFilterTest, InitialValueChanged) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* int_value = new base::Value(1234);
- pref_store_contents_->Set(kAtomicPref, int_value);
+ base::Value* int_value = pref_store_contents_->SetInteger(kAtomicPref, 1234);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
dict_value->SetInteger("c", 56);
dict_value->SetBoolean("d", false);
- pref_store_contents_->Set(kSplitPref, dict_value);
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -1096,14 +1085,13 @@ TEST_P(PrefHashFilterTest, EmptyCleared) {
}
TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::Value* string_value = new base::Value("string value");
- pref_store_contents_->Set(kAtomicPref, string_value);
+ base::Value* string_value =
+ pref_store_contents_->SetString(kAtomicPref, "string value");
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ base::DictionaryValue* dict_value = pref_store_contents_->SetDictionary(
+ kSplitPref, base::MakeUnique<base::DictionaryValue>());
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
- pref_store_contents_->Set(kSplitPref, dict_value);
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
@@ -1150,16 +1138,14 @@ TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
}
TEST_P(PrefHashFilterTest, DontResetReportOnly) {
- // Ownership of these values is transfered to |pref_store_contents_|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::Value* report_only_val = new base::Value(3);
- base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
+ base::Value* int_value1 = pref_store_contents_->SetInteger(kAtomicPref, 1);
+ base::Value* int_value2 = pref_store_contents_->SetInteger(kAtomicPref2, 2);
+ base::Value* report_only_val =
+ pref_store_contents_->SetInteger(kReportOnlyPref, 3);
+ base::DictionaryValue* report_only_split_val =
+ pref_store_contents_->SetDictionary(
+ kReportOnlySplitPref, base::MakeUnique<base::DictionaryValue>());
report_only_split_val->SetInteger("a", 1234);
- pref_store_contents_->Set(kAtomicPref, int_value1);
- pref_store_contents_->Set(kAtomicPref2, int_value2);
- pref_store_contents_->Set(kReportOnlyPref, report_only_val);
- pref_store_contents_->Set(kReportOnlySplitPref, report_only_split_val);
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL));
@@ -1224,14 +1210,11 @@ TEST_P(PrefHashFilterTest, DontResetReportOnly) {
TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) {
base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- base::Value* int_value2 = new base::Value(2);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
- dict_value->Set("a", new base::Value(true));
- root_dict.Set(kAtomicPref, int_value1);
- root_dict.Set(kAtomicPref2, int_value2);
- root_dict.Set(kSplitPref, dict_value);
+ auto dict_value = base::MakeUnique<base::DictionaryValue>();
+ dict_value->SetBoolean("a", true);
+ root_dict.SetInteger(kAtomicPref, 1);
+ root_dict.SetInteger(kAtomicPref2, 2);
+ root_dict.Set(kSplitPref, std::move(dict_value));
// Skip updating kAtomicPref2.
pref_hash_filter_->FilterUpdate(kAtomicPref);
@@ -1273,9 +1256,7 @@ TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) {
TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) {
base::DictionaryValue root_dict;
- // Ownership of the following values is transfered to |root_dict|.
- base::Value* int_value1 = new base::Value(1);
- root_dict.Set(kAtomicPref, int_value1);
+ root_dict.SetInteger(kAtomicPref, 1);
// Only update kAtomicPref.
pref_hash_filter_->FilterUpdate(kAtomicPref);
@@ -1301,16 +1282,14 @@ TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) {
}
TEST_P(PrefHashFilterTest, ExternalValidationValueChanged) {
- // Ownership of this value is transfered to |pref_store_contents_|.
- base::Value* int_value = new base::Value(1234);
- pref_store_contents_->Set(kAtomicPref, int_value);
+ pref_store_contents_->SetInteger(kAtomicPref, 1234);
- base::DictionaryValue* dict_value = new base::DictionaryValue;
+ auto dict_value = base::MakeUnique<base::DictionaryValue>();
dict_value->SetString("a", "foo");
dict_value->SetInteger("b", 1234);
dict_value->SetInteger("c", 56);
dict_value->SetBoolean("d", false);
- pref_store_contents_->Set(kSplitPref, dict_value);
+ pref_store_contents_->Set(kSplitPref, std::move(dict_value));
mock_external_validation_pref_hash_store_->SetCheckResult(
kAtomicPref, ValueState::CHANGED);
diff --git a/chromium/services/preferences/tracked/pref_hash_store_impl.cc b/chromium/services/preferences/tracked/pref_hash_store_impl.cc
index 522b013c5bc..f0cfd319685 100644
--- a/chromium/services/preferences/tracked/pref_hash_store_impl.cc
+++ b/chromium/services/preferences/tracked/pref_hash_store_impl.cc
@@ -90,7 +90,7 @@ PrefHashStoreImpl::~PrefHashStoreImpl() {}
std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
HashStoreContents* storage) {
return std::unique_ptr<PrefHashStoreTransaction>(
- new PrefHashStoreTransactionImpl(this, std::move(storage)));
+ new PrefHashStoreTransactionImpl(this, storage));
}
std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
@@ -126,7 +126,7 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
PrefHashStoreImpl* outer,
HashStoreContents* storage)
: outer_(outer),
- contents_(std::move(storage)),
+ contents_(storage),
super_mac_valid_(false),
super_mac_dirty_(false) {
if (!outer_->use_super_mac_)
diff --git a/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc b/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc
index 3c6ca13126f..18014a8485f 100644
--- a/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc
+++ b/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc
@@ -51,8 +51,8 @@ TEST_F(PrefHashStoreImplTest, ComputeMac) {
TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) {
base::DictionaryValue dict;
- dict.Set("a", new base::Value("string1"));
- dict.Set("b", new base::Value("string2"));
+ dict.SetString("a", "string1");
+ dict.SetString("b", "string2");
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
std::unique_ptr<base::DictionaryValue> computed_macs =
@@ -96,10 +96,10 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
base::DictionaryValue dict;
- dict.Set("a", new base::Value("foo"));
- dict.Set("d", new base::Value("bad"));
- dict.Set("b", new base::Value("bar"));
- dict.Set("c", new base::Value("baz"));
+ dict.SetString("a", "foo");
+ dict.SetString("d", "bad");
+ dict.SetString("b", "bar");
+ dict.SetString("c", "baz");
transaction->StoreHash("path1", &dict);
EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", &dict));
@@ -311,14 +311,14 @@ TEST_F(PrefHashStoreImplTest, SuperMACDisabled) {
TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
base::DictionaryValue dict;
- dict.Set("a", new base::Value("to be replaced"));
- dict.Set("b", new base::Value("same"));
- dict.Set("o", new base::Value("old"));
+ dict.SetString("a", "to be replaced");
+ dict.SetString("b", "same");
+ dict.SetString("o", "old");
base::DictionaryValue modified_dict;
- modified_dict.Set("a", new base::Value("replaced"));
- modified_dict.Set("b", new base::Value("same"));
- modified_dict.Set("c", new base::Value("new"));
+ modified_dict.SetString("a", "replaced");
+ modified_dict.SetString("b", "same");
+ modified_dict.SetString("c", "new");
base::DictionaryValue empty_dict;
@@ -428,7 +428,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
// Store hashes for a random dict to be overwritten below.
base::DictionaryValue initial_dict;
- initial_dict.Set("a", new base::Value("foo"));
+ initial_dict.SetString("a", "foo");
transaction->StoreSplitHash("path1", &initial_dict);
// Verify stored empty dictionary matches NULL and empty dictionary back.
@@ -461,8 +461,8 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
pref_hash_store2.BeginTransaction(GetHashStoreContents()));
base::DictionaryValue tested_dict;
- tested_dict.Set("a", new base::Value("foo"));
- tested_dict.Set("b", new base::Value("bar"));
+ tested_dict.SetString("a", "foo");
+ tested_dict.SetString("b", "bar");
EXPECT_EQ(
ValueState::TRUSTED_UNKNOWN_VALUE,
transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
@@ -480,10 +480,10 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
base::Value string("string1");
base::DictionaryValue dict;
- dict.Set("a", new base::Value("foo"));
- dict.Set("d", new base::Value("bad"));
- dict.Set("b", new base::Value("bar"));
- dict.Set("c", new base::Value("baz"));
+ dict.SetString("a", "foo");
+ dict.SetString("d", "bad");
+ dict.SetString("b", "bar");
+ dict.SetString("c", "baz");
{
PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
index 76ee57f3cd1..354a5bfac4b 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
@@ -6,12 +6,10 @@
#include <windows.h>
-#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
@@ -68,21 +66,43 @@ bool ClearSplitMac(const base::string16& reg_key_name,
return false;
}
+// Deletes |reg_key_name| if it exists.
+void DeleteRegistryKey(const base::string16& reg_key_name) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ LONG result = key.DeleteKey(L"");
+ DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result;
+ }
+}
+
} // namespace
+void TempScopedDirRegistryCleaner::SetRegistryPath(
+ const base::string16& registry_path) {
+ if (registry_path_.empty())
+ registry_path_ = registry_path;
+ else
+ DCHECK_EQ(registry_path_, registry_path);
+}
+
+TempScopedDirRegistryCleaner::~TempScopedDirRegistryCleaner() {
+ DCHECK(!registry_path_.empty());
+ DeleteRegistryKey(registry_path_);
+}
+
RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
const base::string16& registry_path,
- const base::string16& store_key)
+ const base::string16& store_key,
+ scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner)
: preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key),
- reset_on_delete_(base::StartsWith(store_key,
- base::ScopedTempDir::GetTempDirPrefix(),
- base::CompareCase::INSENSITIVE_ASCII)) {
+ temp_dir_cleaner_(std::move(temp_dir_cleaner)) {
+ if (temp_dir_cleaner_)
+ static_cast<TempScopedDirRegistryCleaner*>(temp_dir_cleaner_.get())
+ ->SetRegistryPath(preference_key_name_);
}
-RegistryHashStoreContentsWin::~RegistryHashStoreContentsWin() {
- if (reset_on_delete_)
- Reset();
-}
+RegistryHashStoreContentsWin::~RegistryHashStoreContentsWin() = default;
RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
const RegistryHashStoreContentsWin& other) = default;
@@ -101,12 +121,7 @@ base::StringPiece RegistryHashStoreContentsWin::GetUMASuffix() const {
}
void RegistryHashStoreContentsWin::Reset() {
- base::win::RegKey key;
- if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
- KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- LONG result = key.DeleteKey(L"");
- DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result;
- }
+ DeleteRegistryKey(preference_key_name_);
}
bool RegistryHashStoreContentsWin::GetMac(const std::string& path,
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.h b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
index 0b3b396205d..dd556698157 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
@@ -8,18 +8,29 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "services/preferences/tracked/hash_store_contents.h"
+#include "services/preferences/tracked/temp_scoped_dir_cleaner.h"
+
+// Helper object to clear registry entries for scoped temporary pref stores.
+class TempScopedDirRegistryCleaner : public TempScopedDirCleaner {
+ public:
+ void SetRegistryPath(const base::string16& registry_path);
+
+ private:
+ friend class base::RefCountedThreadSafe<TempScopedDirRegistryCleaner>;
+ ~TempScopedDirRegistryCleaner() override;
+
+ base::string16 registry_path_;
+};
// Implements HashStoreContents by storing MACs in the Windows registry.
class RegistryHashStoreContentsWin : public HashStoreContents {
public:
// Constructs a RegistryHashStoreContents which acts on a registry entry
- // defined by |registry_path| and |store_key|. If |store_key| begins with
- // base::ScopedTempDir::GetTempDirPrefix(), this RegistryHashStoreContentsWin
- // will self Reset() on destruction to avoid proliferating keys in tests that
- // create a profile in a ScopedTempDir (https://crbug.com/721245).
- explicit RegistryHashStoreContentsWin(const base::string16& registry_path,
- const base::string16& store_key);
-
+ // defined by |registry_path| and |store_key|.
+ explicit RegistryHashStoreContentsWin(
+ const base::string16& registry_path,
+ const base::string16& store_key,
+ scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner);
~RegistryHashStoreContentsWin() override;
// HashStoreContents overrides:
@@ -49,7 +60,7 @@ class RegistryHashStoreContentsWin : public HashStoreContents {
const RegistryHashStoreContentsWin& other);
const base::string16 preference_key_name_;
- const bool reset_on_delete_;
+ scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner_;
};
#endif // SERVICES_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
index 468843437fb..d85fdbf1e8b 100644
--- a/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
@@ -4,9 +4,13 @@
#include "services/preferences/tracked/registry_hash_store_contents_win.h"
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h"
+#include "base/threading/thread.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +37,8 @@ class RegistryHashStoreContentsWinTest : public testing::Test {
ASSERT_NO_FATAL_FAILURE(
registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
- contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey));
+ contents.reset(
+ new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey, nullptr));
}
std::unique_ptr<HashStoreContents> contents;
@@ -118,3 +123,90 @@ TEST_F(RegistryHashStoreContentsWinTest, TestReset) {
EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
EXPECT_EQ(0U, split_macs.size());
}
+
+TEST(RegistryHashStoreContentsWinScopedTest, TestScopedDirsCleared) {
+ std::string stored_mac;
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const base::string16 registry_path =
+ temp_dir.GetPath().DirName().BaseName().LossyDisplayName();
+
+ RegistryHashStoreContentsWin verifying_contents(registry_path, kStoreKey,
+ nullptr);
+
+ scoped_refptr<TempScopedDirRegistryCleaner> temp_scoped_dir_cleaner =
+ base::MakeRefCounted<TempScopedDirRegistryCleaner>();
+ std::unique_ptr<RegistryHashStoreContentsWin> contentsA =
+ base::MakeUnique<RegistryHashStoreContentsWin>(registry_path, kStoreKey,
+ temp_scoped_dir_cleaner);
+ std::unique_ptr<RegistryHashStoreContentsWin> contentsB =
+ base::MakeUnique<RegistryHashStoreContentsWin>(registry_path, kStoreKey,
+ temp_scoped_dir_cleaner);
+
+ contentsA->SetMac(kAtomicPrefPath, kTestStringA);
+ contentsB->SetMac(kAtomicPrefPath, kTestStringB);
+
+ temp_scoped_dir_cleaner = nullptr;
+ EXPECT_TRUE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringB, stored_mac);
+
+ contentsB.reset();
+ EXPECT_TRUE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringB, stored_mac);
+
+ contentsA.reset();
+ EXPECT_FALSE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+}
+
+void OffThreadTempScopedDirDestructor(
+ base::string16 registry_path,
+ std::unique_ptr<HashStoreContents> contents) {
+ std::string stored_mac;
+
+ RegistryHashStoreContentsWin verifying_contents(registry_path, kStoreKey,
+ nullptr);
+
+ contents->SetMac(kAtomicPrefPath, kTestStringB);
+ EXPECT_TRUE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringB, stored_mac);
+
+ contents.reset();
+ EXPECT_FALSE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+}
+
+TEST(RegistryHashStoreContentsWinScopedTest, TestScopedDirsClearedMultiThread) {
+ std::string stored_mac;
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const base::string16 registry_path =
+ temp_dir.GetPath().DirName().BaseName().LossyDisplayName();
+
+ RegistryHashStoreContentsWin verifying_contents(registry_path, kStoreKey,
+ nullptr);
+
+ base::Thread test_thread("scoped_dir_cleaner_test_thread");
+ test_thread.StartAndWaitForTesting();
+
+ scoped_refptr<TempScopedDirRegistryCleaner> temp_scoped_dir_cleaner =
+ base::MakeRefCounted<TempScopedDirRegistryCleaner>();
+ std::unique_ptr<RegistryHashStoreContentsWin> contents =
+ base::MakeUnique<RegistryHashStoreContentsWin>(
+ registry_path, kStoreKey, std::move(temp_scoped_dir_cleaner));
+ base::OnceClosure other_thread_closure =
+ base::BindOnce(&OffThreadTempScopedDirDestructor, registry_path,
+ base::Passed(contents->MakeCopy()));
+
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+ contents.reset();
+
+ EXPECT_TRUE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+
+ test_thread.task_runner()->PostTask(FROM_HERE,
+ std::move(other_thread_closure));
+ test_thread.FlushForTesting();
+
+ EXPECT_FALSE(verifying_contents.GetMac(kAtomicPrefPath, &stored_mac));
+}
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.cc b/chromium/services/preferences/tracked/segregated_pref_store.cc
index af7349e0382..ced018e7c67 100644
--- a/chromium/services/preferences/tracked/segregated_pref_store.cc
+++ b/chromium/services/preferences/tracked/segregated_pref_store.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/barrier_closure.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/values.h"
@@ -160,9 +161,12 @@ void SegregatedPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
selected_pref_store_->ReadPrefsAsync(NULL);
}
-void SegregatedPrefStore::CommitPendingWrite() {
- default_pref_store_->CommitPendingWrite();
- selected_pref_store_->CommitPendingWrite();
+void SegregatedPrefStore::CommitPendingWrite(base::OnceClosure done_callback) {
+ base::RepeatingClosure done_callback_wrapper =
+ done_callback ? base::BarrierClosure(2, std::move(done_callback))
+ : base::RepeatingClosure();
+ default_pref_store_->CommitPendingWrite(done_callback_wrapper);
+ selected_pref_store_->CommitPendingWrite(done_callback_wrapper);
}
void SegregatedPrefStore::SchedulePendingLossyWrites() {
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.h b/chromium/services/preferences/tracked/segregated_pref_store.h
index 3621e49aa07..a2b714a4812 100644
--- a/chromium/services/preferences/tracked/segregated_pref_store.h
+++ b/chromium/services/preferences/tracked/segregated_pref_store.h
@@ -72,7 +72,7 @@ class SegregatedPrefStore : public PersistentPrefStore {
PrefReadError GetReadError() const override;
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
- void CommitPendingWrite() override;
+ void CommitPendingWrite(base::OnceClosure done_callback) override;
void SchedulePendingLossyWrites() override;
void ClearMutableValues() override;
diff --git a/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc b/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc
index a237f38285e..d10903620a2 100644
--- a/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc
+++ b/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc
@@ -13,6 +13,8 @@
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "base/values.h"
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_store_observer_mock.h"
@@ -54,9 +56,13 @@ class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
Data* data_;
};
-} // namespace
+enum class CommitPendingWriteMode {
+ WITHOUT_CALLBACK,
+ WITH_CALLBACK,
+};
-class SegregatedPrefStoreTest : public testing::Test {
+class SegregatedPrefStoreTest
+ : public testing::TestWithParam<CommitPendingWriteMode> {
public:
SegregatedPrefStoreTest()
: read_error_delegate_data_(false,
@@ -87,6 +93,8 @@ class SegregatedPrefStoreTest : public testing::Test {
return std::move(read_error_delegate_);
}
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
PrefStoreObserverMock observer_;
scoped_refptr<TestingPrefStore> default_store_;
@@ -99,7 +107,9 @@ class SegregatedPrefStoreTest : public testing::Test {
std::unique_ptr<MockReadErrorDelegate> read_error_delegate_;
};
-TEST_F(SegregatedPrefStoreTest, StoreValues) {
+} // namespace
+
+TEST_P(SegregatedPrefStoreTest, StoreValues) {
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
segregated_store_->ReadPrefs());
@@ -122,7 +132,14 @@ TEST_F(SegregatedPrefStoreTest, StoreValues) {
ASSERT_FALSE(selected_store_->committed());
ASSERT_FALSE(default_store_->committed());
- segregated_store_->CommitPendingWrite();
+ if (GetParam() == CommitPendingWriteMode::WITHOUT_CALLBACK) {
+ segregated_store_->CommitPendingWrite(base::OnceClosure());
+ base::RunLoop().RunUntilIdle();
+ } else {
+ base::RunLoop run_loop;
+ segregated_store_->CommitPendingWrite(run_loop.QuitClosure());
+ run_loop.Run();
+ }
ASSERT_TRUE(selected_store_->committed());
ASSERT_TRUE(default_store_->committed());
@@ -302,3 +319,12 @@ TEST_F(SegregatedPrefStoreTest, GetValues) {
ASSERT_TRUE(values->Get(kSharedPref, &value));
EXPECT_TRUE(base::Value(kValue1).Equals(value));
}
+
+INSTANTIATE_TEST_CASE_P(
+ WithoutCallback,
+ SegregatedPrefStoreTest,
+ ::testing::Values(CommitPendingWriteMode::WITHOUT_CALLBACK));
+INSTANTIATE_TEST_CASE_P(
+ WithCallback,
+ SegregatedPrefStoreTest,
+ ::testing::Values(CommitPendingWriteMode::WITH_CALLBACK));
diff --git a/chromium/services/preferences/tracked/temp_scoped_dir_cleaner.h b/chromium/services/preferences/tracked/temp_scoped_dir_cleaner.h
new file mode 100644
index 00000000000..4359b760bd1
--- /dev/null
+++ b/chromium/services/preferences/tracked/temp_scoped_dir_cleaner.h
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_TRACKED_TEMP_SCOPED_DIR_CLEANER_H_
+#define SERVICES_PREFERENCES_TRACKED_TEMP_SCOPED_DIR_CLEANER_H_
+
+#include "base/memory/ref_counted.h"
+
+// Helper object to clear additional data for scoped temporary pref stores.
+class TempScopedDirCleaner
+ : public base::RefCountedThreadSafe<TempScopedDirCleaner> {
+ protected:
+ friend class base::RefCountedThreadSafe<TempScopedDirCleaner>;
+ virtual ~TempScopedDirCleaner(){};
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_TEMP_SCOPED_DIR_CLEANER_H_
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index ffb5ab2e9ac..2c32319d946 100644
--- a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -16,9 +16,12 @@
#include "services/preferences/tracked/pref_hash_filter.h"
#include "services/preferences/tracked/pref_hash_store_impl.h"
#include "services/preferences/tracked/segregated_pref_store.h"
+#include "services/preferences/tracked/temp_scoped_dir_cleaner.h"
#include "services/preferences/tracked/tracked_preferences_migration.h"
#if defined(OS_WIN)
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_util.h"
#include "services/preferences/tracked/registry_hash_store_contents_win.h"
#endif
@@ -41,16 +44,18 @@ std::unique_ptr<PrefHashStore> CreatePrefHashStore(
std::pair<std::unique_ptr<PrefHashStore>, std::unique_ptr<HashStoreContents>>
GetExternalVerificationPrefHashStorePair(
- const prefs::mojom::TrackedPersistentPrefStoreConfiguration& config) {
+ const prefs::mojom::TrackedPersistentPrefStoreConfiguration& config,
+ scoped_refptr<TempScopedDirCleaner> temp_dir_cleaner) {
#if defined(OS_WIN)
- return std::make_pair(
- base::MakeUnique<PrefHashStoreImpl>(config.registry_seed,
- config.legacy_device_id,
- false /* use_super_mac */),
- base::MakeUnique<RegistryHashStoreContentsWin>(
- config.registry_path, config.unprotected_pref_filename.DirName()
- .BaseName()
- .LossyDisplayName()));
+ return std::make_pair(base::MakeUnique<PrefHashStoreImpl>(
+ config.registry_seed, config.legacy_device_id,
+ false /* use_super_mac */),
+ base::MakeUnique<RegistryHashStoreContentsWin>(
+ config.registry_path,
+ config.unprotected_pref_filename.DirName()
+ .BaseName()
+ .LossyDisplayName(),
+ std::move(temp_dir_cleaner)));
#else
return std::make_pair(nullptr, nullptr);
#endif
@@ -60,10 +65,7 @@ GetExternalVerificationPrefHashStorePair(
PersistentPrefStore* CreateTrackedPersistentPrefStore(
prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
- base::SequencedWorkerPool* worker_pool) {
- auto io_task_runner = JsonPrefStore::GetTaskRunnerForFile(
- config->unprotected_pref_filename.DirName(), worker_pool);
-
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
unprotected_configuration;
std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
@@ -82,15 +84,33 @@ PersistentPrefStore* CreateTrackedPersistentPrefStore(
}
config->tracking_configuration.clear();
+ scoped_refptr<TempScopedDirCleaner> temp_scoped_dir_cleaner;
+#if defined(OS_WIN)
+ // For tests that create a profile in a ScopedTempDir, share a ref_counted
+ // object between the unprotected and protected hash filter's
+ // RegistryHashStoreContentsWin which will clear the registry keys when
+ // destroyed. (https://crbug.com/721245)
+ if (base::StartsWith(config->unprotected_pref_filename.DirName()
+ .BaseName()
+ .LossyDisplayName(),
+ base::ScopedTempDir::GetTempDirPrefix(),
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ temp_scoped_dir_cleaner =
+ base::MakeRefCounted<TempScopedDirRegistryCleaner>();
+ }
+#endif
+
std::unique_ptr<PrefHashFilter> unprotected_pref_hash_filter(
new PrefHashFilter(CreatePrefHashStore(*config, false),
- GetExternalVerificationPrefHashStorePair(*config),
+ GetExternalVerificationPrefHashStorePair(
+ *config, temp_scoped_dir_cleaner),
unprotected_configuration, nullptr,
config->validation_delegate.get(),
config->reporting_ids_count, false));
std::unique_ptr<PrefHashFilter> protected_pref_hash_filter(new PrefHashFilter(
CreatePrefHashStore(*config, true),
- GetExternalVerificationPrefHashStorePair(*config),
+ GetExternalVerificationPrefHashStorePair(*config,
+ temp_scoped_dir_cleaner),
protected_configuration, std::move(config->reset_on_load_observer),
config->validation_delegate.get(), config->reporting_ids_count, true));
@@ -125,9 +145,10 @@ PersistentPrefStore* CreateTrackedPersistentPrefStore(
void InitializeMasterPrefsTracking(
prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr configuration,
base::DictionaryValue* master_prefs) {
- PrefHashFilter(CreatePrefHashStore(*configuration, false),
- GetExternalVerificationPrefHashStorePair(*configuration),
- configuration->tracking_configuration, nullptr, nullptr,
- configuration->reporting_ids_count, false)
+ PrefHashFilter(
+ CreatePrefHashStore(*configuration, false),
+ GetExternalVerificationPrefHashStorePair(*configuration, nullptr),
+ configuration->tracking_configuration, nullptr, nullptr,
+ configuration->reporting_ids_count, false)
.Initialize(master_prefs);
}
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
index fb426bab47d..ca08959b9fd 100644
--- a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
@@ -6,18 +6,17 @@
#define SERVICES_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
#include <utility>
-#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
namespace base {
class DictionaryValue;
-class SequencedWorkerPool;
}
class PersistentPrefStore;
PersistentPrefStore* CreateTrackedPersistentPrefStore(
prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
- base::SequencedWorkerPool* worker_pool);
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
// TODO(sammc): This should move somewhere more appropriate in the longer term.
void InitializeMasterPrefsTracking(
diff --git a/chromium/services/preferences/tracked/tracked_preferences_migration.cc b/chromium/services/preferences/tracked/tracked_preferences_migration.cc
index f2af336e350..61a0c80cf0b 100644
--- a/chromium/services/preferences/tracked/tracked_preferences_migration.cc
+++ b/chromium/services/preferences/tracked/tracked_preferences_migration.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/values.h"
@@ -164,7 +165,8 @@ void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
// |new_store| having equivalently been successfully flushed to disk
// (e.g., on crash or in cases where |new_store| is read-only following
// a read error on startup).
- new_store->Set(pref_name, value_in_old_store->DeepCopy());
+ new_store->Set(pref_name,
+ base::MakeUnique<base::Value>(*value_in_old_store));
migrated_value = true;
*new_store_altered = true;
}
diff --git a/chromium/services/preferences/unittest_helper_manifest.json b/chromium/services/preferences/unittest_helper_manifest.json
new file mode 100644
index 00000000000..2c46470b16d
--- /dev/null
+++ b/chromium/services/preferences/unittest_helper_manifest.json
@@ -0,0 +1,14 @@
+{
+ "name": "prefs_unittest_helper",
+ "display_name": "Prefs Unittest helper",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "test": [ "*" ]
+ },
+ "requires": {
+ "preferences": [ "pref_client" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/preferences/unittest_manifest.json b/chromium/services/preferences/unittest_manifest.json
index df6d7441066..5354cb88376 100644
--- a/chromium/services/preferences/unittest_manifest.json
+++ b/chromium/services/preferences/unittest_manifest.json
@@ -9,7 +9,8 @@
]
},
"requires": {
- "preferences": [ "pref_client", "pref_control" ]
+ "preferences": [ "pref_client" ],
+ "prefs_unittest_helper": [ "test" ]
}
}
}