#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"
-#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/policy/policy_domain_descriptor.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector_factory.h"
+#include "chrome/browser/policy/schema_registry_service.h"
+#include "chrome/browser/policy/schema_registry_service_factory.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/value_store/value_store_change.h"
-#include "chrome/common/extensions/api/storage.h"
#include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_set.h"
+#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/schema.h"
+#include "components/policy/core/common/schema_map.h"
+#include "components/policy/core/common/schema_registry.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
+#include "extensions/browser/api/storage/settings_storage_factory.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/value_store/value_store_change.h"
+#include "extensions/common/api/storage.h"
#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_set.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
-#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/one_shot_event.h"
+using content::BrowserContext;
using content::BrowserThread;
namespace extensions {
-namespace storage = api::storage;
+namespace storage = core_api::storage;
namespace {
const char kLoadSchemasBackgroundTaskTokenName[] =
"load_managed_storage_schemas_token";
+// The Legacy Browser Support was the first user of the policy-for-extensions
+// API, and relied on behavior that will be phased out. If this extension is
+// present then its policies will be loaded in a special way.
+// TODO(joaodasilva): remove this for M35. http://crbug.com/325349
+const char kLegacyBrowserSupportExtensionId[] =
+ "heildphpnddilhkemkielfhnkaagiabh";
+
} // 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.
const content::NotificationDetails& details) OVERRIDE;
private:
- // Loads the schemas of the |extensions| and passes a PolicyDomainDescriptor
- // to RegisterDomain().
- static void LoadSchemas(scoped_ptr<ExtensionSet> extensions,
- base::WeakPtr<ExtensionTracker> self);
- void RegisterDomain(
- scoped_refptr<const policy::PolicyDomainDescriptor> descriptor);
+ // Handler for the signal from ExtensionSystem::ready().
+ void OnExtensionsReady();
+
+ // Starts a schema load for all extensions that use managed storage.
+ void LoadSchemas(scoped_ptr<ExtensionSet> added);
+
+ bool UsesManagedStorage(const Extension* extension) const;
+
+ // Loads the schemas of the |extensions| and passes a ComponentMap to
+ // Register().
+ static void LoadSchemasOnBlockingPool(scoped_ptr<ExtensionSet> extensions,
+ base::WeakPtr<ExtensionTracker> self);
+ void Register(const policy::ComponentMap* components);
Profile* profile_;
content::NotificationRegistrar registrar_;
+ policy::SchemaRegistry* schema_registry_;
base::WeakPtrFactory<ExtensionTracker> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ExtensionTracker);
ManagedValueStoreCache::ExtensionTracker::ExtensionTracker(Profile* profile)
: profile_(profile),
+ schema_registry_(
+ policy::SchemaRegistryServiceFactory::GetForContext(profile)),
weak_factory_(this) {
registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSIONS_READY,
+ chrome::NOTIFICATION_EXTENSION_INSTALLED,
content::Source<Profile>(profile_));
registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSION_LOADED,
- content::Source<Profile>(profile_));
- registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSION_UNLOADED,
+ chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
content::Source<Profile>(profile_));
+
+ // Load schemas when the extension system is ready. It might be ready now.
+ ExtensionSystem::Get(profile_)->ready().Post(
+ FROM_HERE,
+ base::Bind(&ExtensionTracker::OnExtensionsReady,
+ weak_factory_.GetWeakPtr()));
}
void ManagedValueStoreCache::ExtensionTracker::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
+ // Some extensions are installed on the first run before the ExtensionSystem
+ // becomes ready. Wait until all of them are ready before registering the
+ // schemas of managed extensions, so that the policy loaders are reloaded at
+ // most once.
if (!ExtensionSystem::Get(profile_)->ready().is_signaled())
return;
- scoped_refptr<policy::PolicyDomainDescriptor> descriptor(
- new policy::PolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS));
- const ExtensionSet* set =
- ExtensionSystem::Get(profile_)->extension_service()->extensions();
- scoped_ptr<ExtensionSet> managed_extensions(new ExtensionSet());
- for (ExtensionSet::const_iterator it = set->begin(); it != set->end(); ++it) {
- if ((*it)->manifest()->HasPath(manifest_keys::kStorageManagedSchema)) {
- managed_extensions->Insert(*it);
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
+ scoped_ptr<ExtensionSet> added(new ExtensionSet);
+ added->Insert(
+ content::Details<InstalledExtensionInfo>(details)->extension);
+ LoadSchemas(added.Pass());
+ break;
}
+ case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
+ const Extension* removed =
+ content::Details<const Extension>(details).ptr();
+ if (removed && UsesManagedStorage(removed)) {
+ schema_registry_->UnregisterComponent(policy::PolicyNamespace(
+ policy::POLICY_DOMAIN_EXTENSIONS, removed->id()));
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ return;
+ }
+}
+
+void ManagedValueStoreCache::ExtensionTracker::OnExtensionsReady() {
+ // Load schemas for all installed extensions.
+ LoadSchemas(
+ ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet());
+}
- // TODO(joaodasilva): also load extensions that use the storage API for now,
- // to support the Legacy Browser Support extension. Remove this for M30.
- // http://crbug.com/240704
- if ((*it)->HasAPIPermission(APIPermission::kStorage))
- managed_extensions->Insert(*it);
+void ManagedValueStoreCache::ExtensionTracker::LoadSchemas(
+ scoped_ptr<ExtensionSet> added) {
+ // Filter out extensions that don't use managed storage.
+ ExtensionSet::const_iterator it = added->begin();
+ while (it != added->end()) {
+ std::string to_remove;
+ if (!UsesManagedStorage(*it))
+ to_remove = (*it)->id();
+ ++it;
+ if (!to_remove.empty())
+ added->Remove(to_remove);
}
// Load the schema files in a background thread.
BrowserThread::PostBlockingPoolSequencedTask(
kLoadSchemasBackgroundTaskTokenName, FROM_HERE,
- base::Bind(&ExtensionTracker::LoadSchemas,
- base::Passed(&managed_extensions),
+ base::Bind(&ExtensionTracker::LoadSchemasOnBlockingPool,
+ base::Passed(&added),
weak_factory_.GetWeakPtr()));
}
+bool ManagedValueStoreCache::ExtensionTracker::UsesManagedStorage(
+ const Extension* extension) const {
+ if (extension->manifest()->HasPath(manifest_keys::kStorageManagedSchema))
+ return true;
+
+ // TODO(joaodasilva): remove this by M35.
+ return extension->id() == kLegacyBrowserSupportExtensionId;
+}
+
// static
-void ManagedValueStoreCache::ExtensionTracker::LoadSchemas(
+void ManagedValueStoreCache::ExtensionTracker::LoadSchemasOnBlockingPool(
scoped_ptr<ExtensionSet> extensions,
base::WeakPtr<ExtensionTracker> self) {
- scoped_refptr<policy::PolicyDomainDescriptor> descriptor =
- new policy::PolicyDomainDescriptor(policy::POLICY_DOMAIN_EXTENSIONS);
+ DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+ scoped_ptr<policy::ComponentMap> components(new policy::ComponentMap);
for (ExtensionSet::const_iterator it = extensions->begin();
it != extensions->end(); ++it) {
std::string schema_file;
if (!(*it)->manifest()->GetString(
manifest_keys::kStorageManagedSchema, &schema_file)) {
- // TODO(joaodasilva): Remove this for M32. http://crbug.com/240704
- if ((*it)->HasAPIPermission(APIPermission::kStorage)) {
- descriptor->RegisterComponent((*it)->id(),
- scoped_ptr<policy::SchemaOwner>());
- } else {
- NOTREACHED();
- }
+ // TODO(joaodasilva): Remove this. http://crbug.com/325349
+ (*components)[(*it)->id()] = policy::Schema();
continue;
}
// The extension should have been validated, so assume the schema exists
// and is valid.
std::string error;
- scoped_ptr<policy::SchemaOwner> schema =
+ policy::Schema schema =
StorageSchemaManifestHandler::GetSchema(it->get(), &error);
- CHECK(schema) << error;
- descriptor->RegisterComponent((*it)->id(), schema.Pass());
+ CHECK(schema.valid()) << error;
+ (*components)[(*it)->id()] = schema;
}
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&ExtensionTracker::RegisterDomain, self, descriptor));
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&ExtensionTracker::Register, self,
+ base::Owned(components.release())));
}
-void ManagedValueStoreCache::ExtensionTracker::RegisterDomain(
- scoped_refptr<const policy::PolicyDomainDescriptor> descriptor) {
- policy::ProfilePolicyConnector* connector =
- policy::ProfilePolicyConnectorFactory::GetForProfile(profile_);
- connector->policy_service()->RegisterPolicyDomain(descriptor);
+void ManagedValueStoreCache::ExtensionTracker::Register(
+ const policy::ComponentMap* components) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ schema_registry_->RegisterComponents(policy::POLICY_DOMAIN_EXTENSIONS,
+ *components);
+
+ // The first SetReady() call is performed after the ExtensionSystem is 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,
+ BrowserContext* context,
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::FromBrowserContext(context)),
+ policy_service_(policy::ProfilePolicyConnectorFactory::GetForProfile(
+ profile_)->policy_service()),
storage_factory_(factory),
observers_(observers),
- base_path_(profile->GetPath().AppendASCII(
+ 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);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
- 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_);
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
// 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();
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ policy_service_->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
extension_tracker_.reset();
}
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));
- }
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ 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);
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+ // 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.
+ if (!HasStore(extension_id))
+ return;
+ GetStoreFor(extension_id)->DeleteStorage();
+ store_map_.erase(extension_id);
+}
+
+void ManagedValueStoreCache::OnPolicyServiceInitialized(
+ policy::PolicyDomain domain) {
+ DCHECK_CURRENTLY_ON(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));
}
}
void ManagedValueStoreCache::OnPolicyUpdated(const policy::PolicyNamespace& ns,
const policy::PolicyMap& previous,
const policy::PolicyMap& current) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK_CURRENTLY_ON(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,
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.
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+
+ if (!HasStore(extension_id) && current_policy->empty()) {
+ // Don't create the store now if there are no policies configured for this
+ // extension. If the extension uses the storage.managed API then the store
+ // will be created at RunWithValueStoreForExtension().
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();
-}
+ DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-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();
+ 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;
}
-policy::PolicyService* ManagedValueStoreCache::GetPolicyService() {
- policy::ProfilePolicyConnector* connector =
- policy::ProfilePolicyConnectorFactory::GetForProfile(profile_);
- return connector->policy_service();
+bool ManagedValueStoreCache::HasStore(const std::string& extension_id) const {
+ // TODO(joaodasilva): move this check to a ValueStore method.
+ return base::DirectoryExists(base_path_.AppendASCII(extension_id));
}
} // namespace extensions