12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/storage/managed_value_store_cache.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/weak_ptr.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/scoped_observer.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/api/storage/policy_value_store.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/policy/profile_policy_connector.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/policy/profile_policy_connector_factory.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/policy/schema_registry_service.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/policy/schema_registry_service_factory.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_namespace.h"
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "components/policy/core/common/schema.h"
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/schema_map.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/schema_registry.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/storage/settings_storage_factory.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_registry.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_registry_observer.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/value_store/value_store_change.h"
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/api/storage.h"
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "extensions/common/constants.h"
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h"
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest_constants.h"
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/one_shot_event.h"
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using content::BrowserContext;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class ExtensionRegistry;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace storage = core_api::storage;
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kLoadSchemasBackgroundTaskTokenName[] =
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    "load_managed_storage_schemas_token";
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The Legacy Browser Support was the first user of the policy-for-extensions
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// API, and relied on behavior that will be phased out. If this extension is
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// present then its policies will be loaded in a special way.
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(joaodasilva): remove this for M35. http://crbug.com/325349
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const char kLegacyBrowserSupportExtensionId[] =
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    "heildphpnddilhkemkielfhnkaagiabh";
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This helper observes initialization of all the installed extensions and
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// subsequent loads and unloads, and keeps the SchemaRegistry of the Profile
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in sync with the current list of extensions. This allows the PolicyService
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to fetch cloud policy for those extensions, and allows its providers to
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// selectively load only extension policy that has users.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ManagedValueStoreCache::ExtensionTracker
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : public ExtensionRegistryObserver {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit ExtensionTracker(Profile* profile);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ExtensionTracker() {}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ExtensionRegistryObserver implementation.
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void OnExtensionWillBeInstalled(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      content::BrowserContext* browser_context,
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const Extension* extension,
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bool is_update,
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bool from_ephemeral,
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& old_name) OVERRIDE;
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  virtual void OnExtensionUninstalled(
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      content::BrowserContext* browser_context,
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const Extension* extension,
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::UninstallReason reason) OVERRIDE;
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Handler for the signal from ExtensionSystem::ready().
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnExtensionsReady();
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Starts a schema load for all extensions that use managed storage.
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void LoadSchemas(scoped_ptr<ExtensionSet> added);
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool UsesManagedStorage(const Extension* extension) const;
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Loads the schemas of the |extensions| and passes a ComponentMap to
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Register().
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  static void LoadSchemasOnBlockingPool(scoped_ptr<ExtensionSet> extensions,
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                        base::WeakPtr<ExtensionTracker> self);
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  void Register(const policy::ComponentMap* components);
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Profile* profile_;
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      extension_registry_observer_;
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  policy::SchemaRegistry* schema_registry_;
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::WeakPtrFactory<ExtensionTracker> weak_factory_;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ExtensionTracker);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ManagedValueStoreCache::ExtensionTracker::ExtensionTracker(Profile* profile)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile),
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      extension_registry_observer_(this),
1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      schema_registry_(policy::SchemaRegistryServiceFactory::GetForContext(
1136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                           profile)->registry()),
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      weak_factory_(this) {
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Load schemas when the extension system is ready. It might be ready now.
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ExtensionSystem::Get(profile_)->ready().Post(
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FROM_HERE,
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ExtensionTracker::OnExtensionsReady,
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::OnExtensionWillBeInstalled(
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserContext* browser_context,
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension,
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool is_update,
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool from_ephemeral,
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& old_name) {
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Some extensions are installed on the first run before the ExtensionSystem
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // becomes ready. Wait until all of them are ready before registering the
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // schemas of managed extensions, so that the policy loaders are reloaded at
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // most once.
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!ExtensionSystem::Get(profile_)->ready().is_signaled())
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<ExtensionSet> added(new ExtensionSet);
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  added->Insert(extension);
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LoadSchemas(added.Pass());
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::OnExtensionUninstalled(
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserContext* browser_context,
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const Extension* extension,
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    extensions::UninstallReason reason) {
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!ExtensionSystem::Get(profile_)->ready().is_signaled())
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (extension && UsesManagedStorage(extension)) {
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    schema_registry_->UnregisterComponent(policy::PolicyNamespace(
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        policy::POLICY_DOMAIN_EXTENSIONS, extension->id()));
149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::OnExtensionsReady() {
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Load schemas for all installed extensions.
15423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  LoadSchemas(
15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      ExtensionRegistry::Get(profile_)->GenerateInstalledExtensionsSet());
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::LoadSchemas(
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<ExtensionSet> added) {
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Filter out extensions that don't use managed storage.
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ExtensionSet::const_iterator it = added->begin();
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  while (it != added->end()) {
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string to_remove;
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!UsesManagedStorage(it->get()))
165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      to_remove = (*it)->id();
166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ++it;
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!to_remove.empty())
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      added->Remove(to_remove);
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Load the schema files in a background thread.
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  BrowserThread::PostBlockingPoolSequencedTask(
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      kLoadSchemasBackgroundTaskTokenName, FROM_HERE,
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ExtensionTracker::LoadSchemasOnBlockingPool,
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 base::Passed(&added),
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ManagedValueStoreCache::ExtensionTracker::UsesManagedStorage(
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const Extension* extension) const {
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (extension->manifest()->HasPath(manifest_keys::kStorageManagedSchema))
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return true;
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // TODO(joaodasilva): remove this by M35.
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return extension->id() == kLegacyBrowserSupportExtensionId;
186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// static
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::LoadSchemasOnBlockingPool(
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_ptr<ExtensionSet> extensions,
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::WeakPtr<ExtensionTracker> self) {
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<policy::ComponentMap> components(new policy::ComponentMap);
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (ExtensionSet::const_iterator it = extensions->begin();
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != extensions->end(); ++it) {
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string schema_file;
19890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!(*it)->manifest()->GetString(
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            manifest_keys::kStorageManagedSchema, &schema_file)) {
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // TODO(joaodasilva): Remove this. http://crbug.com/325349
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (*components)[(*it)->id()] = policy::Schema();
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // The extension should have been validated, so assume the schema exists
20590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // and is valid.
20690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::string error;
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    policy::Schema schema =
2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        StorageSchemaManifestHandler::GetSchema(it->get(), &error);
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // If the schema is invalid then proceed with an empty schema. The extension
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // will be listed in chrome://policy but won't be able to load any policies.
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!schema.valid())
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      schema = policy::Schema();
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    (*components)[(*it)->id()] = schema;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          base::Bind(&ExtensionTracker::Register, self,
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     base::Owned(components.release())));
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ManagedValueStoreCache::ExtensionTracker::Register(
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const policy::ComponentMap* components) {
223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_registry_->RegisterComponents(policy::POLICY_DOMAIN_EXTENSIONS,
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                       *components);
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
22723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // The first SetReady() call is performed after the ExtensionSystem is ready,
22823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // even if there are no managed extensions. It will trigger a loading of the
22923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // initial policy for any managed extensions, and eventually the PolicyService
23023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // will become ready for POLICY_DOMAIN_EXTENSIONS, and
23123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // OnPolicyServiceInitialized() will be invoked.
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Subsequent calls to SetReady() are ignored.
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  schema_registry_->SetReady(policy::POLICY_DOMAIN_EXTENSIONS);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ManagedValueStoreCache::ManagedValueStoreCache(
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BrowserContext* context,
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<SettingsStorageFactory>& factory,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<SettingsObserverList>& observers)
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : profile_(Profile::FromBrowserContext(context)),
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      policy_service_(policy::ProfilePolicyConnectorFactory::GetForProfile(
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          profile_)->policy_service()),
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      storage_factory_(factory),
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      observers_(observers),
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base_path_(profile_->GetPath().AppendASCII(
24668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          extensions::kManagedSettingsDirectoryName)) {
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  policy_service_->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extension_tracker_.reset(new ExtensionTracker(profile_));
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (policy_service_->IsInitializationComplete(
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          policy::POLICY_DOMAIN_EXTENSIONS)) {
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnPolicyServiceInitialized(policy::POLICY_DOMAIN_EXTENSIONS);
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ManagedValueStoreCache::~ManagedValueStoreCache() {
260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Delete the PolicyValueStores on FILE.
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  store_map_.clear();
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManagedValueStoreCache::ShutdownOnUI() {
266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  policy_service_->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extension_tracker_.reset();
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManagedValueStoreCache::RunWithValueStoreForExtension(
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StorageCallback& callback,
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<const Extension> extension) {
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  callback.Run(GetStoreFor(extension->id()));
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManagedValueStoreCache::DeleteStorageSoon(
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id) {
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // It's possible that the store exists, but hasn't been loaded yet
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // (because the extension is unloaded, for example). Open the database to
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // clear it if it exists.
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!HasStore(extension_id))
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  GetStoreFor(extension_id)->DeleteStorage();
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  store_map_.erase(extension_id);
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ManagedValueStoreCache::OnPolicyServiceInitialized(
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    policy::PolicyDomain domain) {
292effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (domain != policy::POLICY_DOMAIN_EXTENSIONS)
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The PolicyService now has all the initial policies ready. Send policy
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // for all the managed extensions to their backing stores now.
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  policy::SchemaRegistry* registry =
3006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      policy::SchemaRegistryServiceFactory::GetForContext(profile_)->registry();
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const policy::ComponentMap* map = registry->schema_map()->GetComponents(
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      policy::POLICY_DOMAIN_EXTENSIONS);
303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!map)
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const policy::PolicyMap empty_map;
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (policy::ComponentMap::const_iterator it = map->begin();
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != map->end(); ++it) {
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS,
310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     it->first);
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // If there is no policy for |ns| then this will clear the previous store,
312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // if there is one.
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    OnPolicyUpdated(ns, empty_map, policy_service_->GetPolicies(ns));
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManagedValueStoreCache::OnPolicyUpdated(const policy::PolicyNamespace& ns,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const policy::PolicyMap& previous,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const policy::PolicyMap& current) {
320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!policy_service_->IsInitializationComplete(
323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)           policy::POLICY_DOMAIN_EXTENSIONS)) {
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // OnPolicyUpdated is called whenever a policy changes, but it doesn't
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // mean that all the policy providers are ready; wait until we get the
326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // final policy values before passing them to the store.
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ManagedValueStoreCache::UpdatePolicyOnFILE,
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this),
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 ns.component_id,
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Passed(current.DeepCopy())));
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ManagedValueStoreCache::UpdatePolicyOnFILE(
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id,
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<policy::PolicyMap> current_policy) {
341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!HasStore(extension_id) && current_policy->empty()) {
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Don't create the store now if there are no policies configured for this
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // extension. If the extension uses the storage.managed API then the store
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // will be created at RunWithValueStoreForExtension().
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  GetStoreFor(extension_id)->SetCurrentPolicy(*current_policy);
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PolicyValueStore* ManagedValueStoreCache::GetStoreFor(
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id) {
355effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PolicyValueStoreMap::iterator it = store_map_.find(extension_id);
358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (it != store_map_.end())
359f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return it->second.get();
360f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
361f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Create the store now, and serve the cached policy until the PolicyService
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // sends updated values.
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PolicyValueStore* store = new PolicyValueStore(
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extension_id,
365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      observers_,
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      make_scoped_ptr(storage_factory_->Create(base_path_, extension_id)));
367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  store_map_[extension_id] = make_linked_ptr(store);
368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return store;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool ManagedValueStoreCache::HasStore(const std::string& extension_id) const {
373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TODO(joaodasilva): move this check to a ValueStore method.
374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return base::DirectoryExists(base_path_.AppendASCII(extension_id));
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
378