| // 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->Clone(), |
| registry_->GetRegistrationFlags(key)); |
| } |
| |
| connection->ProvideDefaults(std::move(defaults)); |
| } |
| |
| } // namespace prefs |