| Index: chrome/browser/extensions/api/storage/managed_value_store_cache.cc
|
| diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
|
| index cf4b01057fbfb3bcaea64b88739a5c336b12c219..a4619dbedc57a855a2a63f5dc8610aaa07977875 100644
|
| --- a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
|
| +++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
|
| @@ -9,8 +9,7 @@
|
| #include "base/callback.h"
|
| #include "base/file_util.h"
|
| #include "base/logging.h"
|
| -#include "base/memory/ref_counted.h"
|
| -#include "base/message_loop/message_loop_proxy.h"
|
| +#include "base/memory/weak_ptr.h"
|
| #include "chrome/browser/chrome_notification_types.h"
|
| #include "chrome/browser/extensions/api/storage/policy_value_store.h"
|
| #include "chrome/browser/extensions/api/storage/settings_storage_factory.h"
|
| @@ -19,6 +18,7 @@
|
| #include "chrome/browser/extensions/extension_system.h"
|
| #include "chrome/browser/policy/profile_policy_connector.h"
|
| #include "chrome/browser/policy/profile_policy_connector_factory.h"
|
| +#include "chrome/browser/policy/schema_map.h"
|
| #include "chrome/browser/policy/schema_registry.h"
|
| #include "chrome/browser/policy/schema_registry_service.h"
|
| #include "chrome/browser/policy/schema_registry_service_factory.h"
|
| @@ -54,7 +54,7 @@ const char kLoadSchemasBackgroundTaskTokenName[] =
|
| } // namespace
|
|
|
| // This helper observes initialization of all the installed extensions and
|
| -// subsequent loads and unloads, and keeps the PolicyService of the Profile
|
| +// subsequent loads and unloads, and keeps the SchemaRegistry of the Profile
|
| // in sync with the current list of extensions. This allows the PolicyService
|
| // to fetch cloud policy for those extensions, and allows its providers to
|
| // selectively load only extension policy that has users.
|
| @@ -149,9 +149,6 @@ void ManagedValueStoreCache::ExtensionTracker::Observe(
|
| added->Remove(to_remove);
|
| }
|
|
|
| - if (added->is_empty())
|
| - return;
|
| -
|
| // Load the schema files in a background thread.
|
| BrowserThread::PostBlockingPoolSequencedTask(
|
| kLoadSchemasBackgroundTaskTokenName, FROM_HERE,
|
| @@ -211,44 +208,48 @@ void ManagedValueStoreCache::ExtensionTracker::Register(
|
| const policy::ComponentMap* components) {
|
| schema_registry_->RegisterComponents(policy::POLICY_DOMAIN_EXTENSIONS,
|
| *components);
|
| +
|
| + // The first SetReady() call is performed after receiving
|
| + // NOTIFICATION_EXTENSIONS_READY, even if there are no managed extensions.
|
| + // It will trigger a loading of the initial policy for any managed
|
| + // extensions, and eventually the PolicyService will become ready for
|
| + // POLICY_DOMAIN_EXTENSIONS, and OnPolicyServiceInitialized() will be invoked.
|
| + // Subsequent calls to SetReady() are ignored.
|
| + schema_registry_->SetReady(policy::POLICY_DOMAIN_EXTENSIONS);
|
| }
|
|
|
| ManagedValueStoreCache::ManagedValueStoreCache(
|
| Profile* profile,
|
| const scoped_refptr<SettingsStorageFactory>& factory,
|
| const scoped_refptr<SettingsObserverList>& observers)
|
| - : weak_factory_(this),
|
| - weak_this_on_ui_(weak_factory_.GetWeakPtr()),
|
| - profile_(profile),
|
| - event_router_(ExtensionSystem::Get(profile)->event_router()),
|
| + : profile_(profile),
|
| + policy_service_(policy::ProfilePolicyConnectorFactory::GetForProfile(
|
| + profile)->policy_service()),
|
| storage_factory_(factory),
|
| observers_(observers),
|
| base_path_(profile->GetPath().AppendASCII(
|
| extensions::kManagedSettingsDirectoryName)) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - // |event_router_| can be NULL on unit_tests.
|
| - if (event_router_)
|
| - event_router_->RegisterObserver(this, storage::OnChanged::kEventName);
|
|
|
| - GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
|
| + policy_service_->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
|
|
|
| extension_tracker_.reset(new ExtensionTracker(profile_));
|
| +
|
| + if (policy_service_->IsInitializationComplete(
|
| + policy::POLICY_DOMAIN_EXTENSIONS)) {
|
| + OnPolicyServiceInitialized(policy::POLICY_DOMAIN_EXTENSIONS);
|
| + }
|
| }
|
|
|
| ManagedValueStoreCache::~ManagedValueStoreCache() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - DCHECK(!event_router_);
|
| // Delete the PolicyValueStores on FILE.
|
| store_map_.clear();
|
| }
|
|
|
| void ManagedValueStoreCache::ShutdownOnUI() {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - GetPolicyService()->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
|
| - if (event_router_)
|
| - event_router_->UnregisterObserver(this);
|
| - event_router_ = NULL;
|
| - weak_factory_.InvalidateWeakPtrs();
|
| + policy_service_->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
|
| extension_tracker_.reset();
|
| }
|
|
|
| @@ -256,43 +257,46 @@ void ManagedValueStoreCache::RunWithValueStoreForExtension(
|
| const StorageCallback& callback,
|
| scoped_refptr<const Extension> extension) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - PolicyValueStore* store = GetStoreFor(extension->id());
|
| - if (store) {
|
| - callback.Run(store);
|
| - } else {
|
| - // First time that an extension calls storage.managed.get(). Create the
|
| - // store and load it with the current policy, and don't send event
|
| - // notifications.
|
| - CreateStoreFor(
|
| - extension->id(),
|
| - false,
|
| - base::Bind(&ManagedValueStoreCache::RunWithValueStoreForExtension,
|
| - base::Unretained(this),
|
| - callback,
|
| - extension));
|
| - }
|
| + callback.Run(GetStoreFor(extension->id()));
|
| }
|
|
|
| void ManagedValueStoreCache::DeleteStorageSoon(
|
| const std::string& extension_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - PolicyValueStore* store = GetStoreFor(extension_id);
|
| - if (!store) {
|
| - // It's possible that the store exists, but hasn't been loaded yet
|
| - // (because the extension is unloaded, for example). Open the database to
|
| - // clear it if it exists.
|
| - // TODO(joaodasilva): move this check to a ValueStore method.
|
| - if (base::DirectoryExists(base_path_.AppendASCII(extension_id))) {
|
| - CreateStoreFor(
|
| - extension_id,
|
| - false,
|
| - base::Bind(&ManagedValueStoreCache::DeleteStorageSoon,
|
| - base::Unretained(this),
|
| - extension_id));
|
| - }
|
| - } else {
|
| - store->DeleteStorage();
|
| - store_map_.erase(extension_id);
|
| + // It's possible that the store exists, but hasn't been loaded yet
|
| + // (because the extension is unloaded, for example). Open the database to
|
| + // clear it if it exists.
|
| + // TODO(joaodasilva): move this check to a ValueStore method.
|
| + if (!base::DirectoryExists(base_path_.AppendASCII(extension_id)))
|
| + return;
|
| + GetStoreFor(extension_id)->DeleteStorage();
|
| + store_map_.erase(extension_id);
|
| +}
|
| +
|
| +void ManagedValueStoreCache::OnPolicyServiceInitialized(
|
| + policy::PolicyDomain domain) {
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + if (domain != policy::POLICY_DOMAIN_EXTENSIONS)
|
| + return;
|
| +
|
| + // The PolicyService now has all the initial policies ready. Send policy
|
| + // for all the managed extensions to their backing stores now.
|
| + policy::SchemaRegistry* registry =
|
| + policy::SchemaRegistryServiceFactory::GetForContext(profile_);
|
| + const policy::ComponentMap* map = registry->schema_map()->GetComponents(
|
| + policy::POLICY_DOMAIN_EXTENSIONS);
|
| + if (!map)
|
| + return;
|
| +
|
| + const policy::PolicyMap empty_map;
|
| + for (policy::ComponentMap::const_iterator it = map->begin();
|
| + it != map->end(); ++it) {
|
| + const policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS,
|
| + it->first);
|
| + // If there is no policy for |ns| then this will clear the previous store,
|
| + // if there is one.
|
| + OnPolicyUpdated(ns, empty_map, policy_service_->GetPolicies(ns));
|
| }
|
| }
|
|
|
| @@ -300,6 +304,15 @@ void ManagedValueStoreCache::OnPolicyUpdated(const policy::PolicyNamespace& ns,
|
| const policy::PolicyMap& previous,
|
| const policy::PolicyMap& current) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| +
|
| + if (!policy_service_->IsInitializationComplete(
|
| + policy::POLICY_DOMAIN_EXTENSIONS)) {
|
| + // OnPolicyUpdated is called whenever a policy changes, but it doesn't
|
| + // mean that all the policy providers are ready; wait until we get the
|
| + // final policy values before passing them to the store.
|
| + return;
|
| + }
|
| +
|
| BrowserThread::PostTask(
|
| BrowserThread::FILE, FROM_HERE,
|
| base::Bind(&ManagedValueStoreCache::UpdatePolicyOnFILE,
|
| @@ -312,147 +325,26 @@ void ManagedValueStoreCache::UpdatePolicyOnFILE(
|
| const std::string& extension_id,
|
| scoped_ptr<policy::PolicyMap> current_policy) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - PolicyValueStore* store = GetStoreFor(extension_id);
|
| - if (!store) {
|
| - // The extension hasn't executed any storage.managed.* calls, and isn't
|
| - // listening for onChanged() either. Ignore this notification in that case.
|
| - return;
|
| - }
|
| - // Update the policy on the backing store, and fire notifications if it
|
| - // changed.
|
| - store->SetCurrentPolicy(*current_policy, true);
|
| -}
|
| -
|
| -void ManagedValueStoreCache::OnListenerAdded(
|
| - const EventListenerInfo& details) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK_EQ(std::string(storage::OnChanged::kEventName), details.event_name);
|
| - // This is invoked on several occasions:
|
| - //
|
| - // 1. when an extension first registers to observe storage.onChanged; in this
|
| - // case the backend doesn't have any previous data persisted, and it won't
|
| - // trigger a notification.
|
| - //
|
| - // 2. when the browser starts up and all existing extensions re-register for
|
| - // the onChanged event. In this case, if the current policy differs from
|
| - // the persisted version then a notification will be sent.
|
| - //
|
| - // 3. a policy update just occurred and sent a notification, and an extension
|
| - // with EventPages that is observing onChanged just woke up and registed
|
| - // again. In this case the policy update already persisted the current
|
| - // policy version, and |store| already exists.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::FILE, FROM_HERE,
|
| - base::Bind(&ManagedValueStoreCache::CreateForExtensionOnFILE,
|
| - base::Unretained(this),
|
| - details.extension_id));
|
| -}
|
| -
|
| -void ManagedValueStoreCache::CreateForExtensionOnFILE(
|
| - const std::string& extension_id) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - PolicyValueStore* store = GetStoreFor(extension_id);
|
| - if (!store)
|
| - CreateStoreFor(extension_id, true, base::Closure());
|
| + GetStoreFor(extension_id)->SetCurrentPolicy(*current_policy);
|
| }
|
|
|
| PolicyValueStore* ManagedValueStoreCache::GetStoreFor(
|
| const std::string& extension_id) {
|
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - PolicyValueStoreMap::iterator it = store_map_.find(extension_id);
|
| - if (it == store_map_.end())
|
| - return NULL;
|
| - return it->second.get();
|
| -}
|
| -
|
| -void ManagedValueStoreCache::CreateStoreFor(
|
| - const std::string& extension_id,
|
| - bool notify_if_changed,
|
| - const base::Closure& continuation) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - DCHECK(!GetStoreFor(extension_id));
|
| - // Creating or loading an existing database requires an immediate update
|
| - // with the current policy for the corresponding extension, which must be
|
| - // retrieved on UI.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&ManagedValueStoreCache::GetInitialPolicy,
|
| - weak_this_on_ui_,
|
| - extension_id,
|
| - notify_if_changed,
|
| - continuation));
|
| -}
|
| -
|
| -void ManagedValueStoreCache::GetInitialPolicy(
|
| - const std::string& extension_id,
|
| - bool notify_if_changed,
|
| - const base::Closure& continuation) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - policy::PolicyService* policy_service = GetPolicyService();
|
| -
|
| - // If initialization of POLICY_DOMAIN_EXTENSIONS isn't complete then all the
|
| - // policies served are empty; let the extension see what's cached in LevelDB
|
| - // in that case. The PolicyService will issue notifications once new policies
|
| - // are ready.
|
| - scoped_ptr<policy::PolicyMap> policy;
|
| - if (policy_service->IsInitializationComplete(
|
| - policy::POLICY_DOMAIN_EXTENSIONS)) {
|
| - policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS, extension_id);
|
| - policy = policy_service->GetPolicies(ns).DeepCopy();
|
| - }
|
| -
|
| - // Now post back to FILE to create the database.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::FILE, FROM_HERE,
|
| - base::Bind(&ManagedValueStoreCache::CreateStoreWithInitialPolicy,
|
| - base::Unretained(this),
|
| - extension_id,
|
| - notify_if_changed,
|
| - base::Passed(&policy),
|
| - continuation));
|
| -}
|
| -
|
| -void ManagedValueStoreCache::CreateStoreWithInitialPolicy(
|
| - const std::string& extension_id,
|
| - bool notify_if_changed,
|
| - scoped_ptr<policy::PolicyMap> initial_policy,
|
| - const base::Closure& continuation) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
|
| - // If a 2nd call to CreateStoreFor() is issued before the 1st gets to execute
|
| - // its UI task, then the 2nd will enter this function but the store has
|
| - // already been created. Check for that.
|
| - PolicyValueStore* store = GetStoreFor(extension_id);
|
| -
|
| - if (!store) {
|
| - // Create it now.
|
| -
|
| - // If the database doesn't exist yet then this is the initial install,
|
| - // and no notifications should be issued in that case.
|
| - // TODO(joaodasilva): move this check to a ValueStore method.
|
| - if (!base::DirectoryExists(base_path_.AppendASCII(extension_id)))
|
| - notify_if_changed = false;
|
| -
|
| - store = new PolicyValueStore(
|
| - extension_id,
|
| - observers_,
|
| - make_scoped_ptr(storage_factory_->Create(base_path_, extension_id)));
|
| - store_map_[extension_id] = make_linked_ptr(store);
|
| - }
|
| -
|
| - // Send the latest policy to the store, if it's already available.
|
| - if (initial_policy)
|
| - store->SetCurrentPolicy(*initial_policy, notify_if_changed);
|
|
|
| - // And finally resume from where this process started.
|
| - if (!continuation.is_null())
|
| - continuation.Run();
|
| -}
|
| -
|
| -policy::PolicyService* ManagedValueStoreCache::GetPolicyService() {
|
| - policy::ProfilePolicyConnector* connector =
|
| - policy::ProfilePolicyConnectorFactory::GetForProfile(profile_);
|
| - return connector->policy_service();
|
| + PolicyValueStoreMap::iterator it = store_map_.find(extension_id);
|
| + if (it != store_map_.end())
|
| + return it->second.get();
|
| +
|
| + // Create the store now, and serve the cached policy until the PolicyService
|
| + // sends updated values.
|
| + PolicyValueStore* store = new PolicyValueStore(
|
| + extension_id,
|
| + observers_,
|
| + make_scoped_ptr(storage_factory_->Create(base_path_, extension_id)));
|
| + store_map_[extension_id] = make_linked_ptr(store);
|
| +
|
| + return store;
|
| }
|
|
|
| } // namespace extensions
|
|
|