blob: 615d26d8e608748a35446cfc18e88f936f687fa7 [file] [log] [blame]
// 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_service_factory.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.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"
#include "components/prefs/pref_service.h"
#include "components/prefs/pref_value_store.h"
#include "services/preferences/public/cpp/persistent_pref_store_client.h"
#include "services/preferences/public/cpp/pref_registry_serializer.h"
#include "services/preferences/public/cpp/pref_store_client.h"
#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace prefs {
namespace {
// Used to implement a "fire and forget" pattern where we call an interface
// method, with an attached error handler, but don't care to hold on to the
// InterfacePtr after.
template <typename Interface>
class RefCountedInterfacePtr
: public base::RefCounted<RefCountedInterfacePtr<Interface>> {
public:
mojo::InterfacePtr<Interface>& get() { return ptr_; }
void reset() { ptr_.reset(); }
private:
friend class base::RefCounted<RefCountedInterfacePtr<Interface>>;
~RefCountedInterfacePtr() = default;
mojo::InterfacePtr<Interface> ptr_;
};
scoped_refptr<PrefStore> CreatePrefStoreClient(
PrefValueStore::PrefStoreType store_type,
base::flat_map<PrefValueStore::PrefStoreType,
mojom::PrefStoreConnectionPtr>* connections) {
auto pref_store_it = connections->find(store_type);
if (pref_store_it != connections->end()) {
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 {
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);
}
}
void OnConnect(
scoped_refptr<RefCountedInterfacePtr<mojom::PrefStoreConnector>>
connector_ptr,
scoped_refptr<PrefRegistry> pref_registry,
ConnectCallback callback,
mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
mojom::IncognitoPersistentPrefStoreConnectionPtr incognito_connection,
std::vector<mojom::PrefRegistrationPtr> defaults,
base::flat_map<PrefValueStore::PrefStoreType, mojom::PrefStoreConnectionPtr>
connections) {
scoped_refptr<PrefStore> managed_prefs =
CreatePrefStoreClient(PrefValueStore::MANAGED_STORE, &connections);
scoped_refptr<PrefStore> supervised_user_prefs = CreatePrefStoreClient(
PrefValueStore::SUPERVISED_USER_STORE, &connections);
scoped_refptr<PrefStore> extension_prefs =
CreatePrefStoreClient(PrefValueStore::EXTENSION_STORE, &connections);
scoped_refptr<PrefStore> command_line_prefs =
CreatePrefStoreClient(PrefValueStore::COMMAND_LINE_STORE, &connections);
scoped_refptr<PrefStore> recommended_prefs =
CreatePrefStoreClient(PrefValueStore::RECOMMENDED_STORE, &connections);
RegisterRemoteDefaults(pref_registry.get(), std::move(defaults));
scoped_refptr<PersistentPrefStore> persistent_pref_store(
new PersistentPrefStoreClient(
std::move(persistent_pref_store_connection)));
if (incognito_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.
auto overlay_pref_store = base::MakeRefCounted<OverlayUserPrefStore>(
persistent_pref_store.get(),
new PersistentPrefStoreClient(
std::move(incognito_connection->pref_store_connection)));
for (const auto& persistent_pref_name :
incognito_connection->persistent_pref_names) {
overlay_pref_store->RegisterPersistentPref(persistent_pref_name);
}
persistent_pref_store = overlay_pref_store;
}
auto pref_notifier = std::make_unique<PrefNotifierImpl>();
auto pref_value_store = std::make_unique<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.get());
auto pref_service = std::make_unique<PrefService>(
std::move(pref_notifier), std::move(pref_value_store),
persistent_pref_store.get(), pref_registry.get(), base::DoNothing(),
true);
switch (pref_service->GetAllPrefStoresInitializationStatus()) {
case PrefService::INITIALIZATION_STATUS_WAITING:
pref_service->AddPrefInitObserver(
base::BindOnce(&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();
}
void OnConnectError(
scoped_refptr<RefCountedInterfacePtr<mojom::PrefStoreConnector>>
connector_ptr,
ConnectCallback callback) {
callback.Run(nullptr);
connector_ptr->reset();
}
} // namespace
void ConnectToPrefService(mojom::PrefStoreConnectorPtr connector,
scoped_refptr<PrefRegistry> pref_registry,
ConnectCallback callback) {
auto connector_ptr =
base::MakeRefCounted<RefCountedInterfacePtr<mojom::PrefStoreConnector>>();
connector_ptr->get() = std::move(connector);
connector_ptr->get().set_connection_error_handler(base::Bind(
&OnConnectError, connector_ptr, base::Passed(ConnectCallback{callback})));
auto serialized_pref_registry = SerializePrefRegistry(*pref_registry);
connector_ptr->get()->Connect(
std::move(serialized_pref_registry),
base::BindOnce(&OnConnect, connector_ptr, std::move(pref_registry),
std::move(callback)));
}
void ConnectToPrefService(service_manager::Connector* connector,
scoped_refptr<PrefRegistry> pref_registry,
ConnectCallback callback,
base::StringPiece service_name) {
mojom::PrefStoreConnectorPtr pref_connector;
connector->BindInterface(service_name.as_string(), &pref_connector);
ConnectToPrefService(std::move(pref_connector), std::move(pref_registry),
std::move(callback));
}
} // namespace prefs