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 |