Chromium Code Reviews| 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..5005b2ddc21f5a3403db34aecec971e845e7d91d 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" |
| @@ -54,7 +53,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 +148,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 +207,47 @@ 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. |
|
bartfab (slow)
2013/11/11 14:40:08
Nit: Maybe add a sentence that explains any furthe
Joao da Silva
2013/11/12 15:26:33
Done.
|
| + 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 +255,43 @@ 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) { |
| + 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( |
|
bartfab (slow)
2013/11/11 14:40:08
Nit: #include "chrome/browser/policy/schema_map.h"
Joao da Silva
2013/11/12 15:26:33
Done.
|
| + policy::POLICY_DOMAIN_EXTENSIONS); |
| + if (!map) |
| + return; |
| + |
| + const policy::PolicyMap empty_map; |
| + for (policy::ComponentMap::const_iterator it = map->begin(); |
| + it != map->end(); ++it) { |
| + policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS, it->first); |
|
bartfab (slow)
2013/11/11 14:40:08
Nit: Const - or just create it inline.
Joao da Silva
2013/11/12 15:26:33
Done.
|
| + // 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 +299,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 updated whenever a policy changes, but it doesn't |
|
bartfab (slow)
2013/11/11 14:40:08
Nit: s/updated/called/
Joao da Silva
2013/11/12 15:26:33
Done.
|
| + // 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 +320,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 |