Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / declarative / rules_registry_service.cc
blobbca6fd5bb2dbba2156c2b1dfc8abf93a4f53cec3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/declarative/rules_registry_service.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "extensions/browser/api/declarative/rules_cache_delegate.h"
14 #include "extensions/browser/api/declarative_content/content_rules_registry.h"
15 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
16 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
17 #include "extensions/browser/api/extensions_api_client.h"
18 #include "extensions/browser/api/web_request/web_request_api.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/common/extension.h"
22 namespace extensions {
24 namespace {
26 // Registers |web_request_rules_registry| on the IO thread.
27 void RegisterToExtensionWebRequestEventRouterOnIO(
28 content::BrowserContext* browser_context,
29 int rules_registry_id,
30 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) {
31 ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
32 browser_context, rules_registry_id, web_request_rules_registry);
35 void NotifyWithExtensionSafe(
36 scoped_refptr<const Extension> extension,
37 void (RulesRegistry::*notification_callback)(const Extension*),
38 scoped_refptr<RulesRegistry> registry) {
39 (registry.get()->*notification_callback)(extension.get());
42 } // namespace
44 const int RulesRegistryService::kDefaultRulesRegistryID = 0;
45 const int RulesRegistryService::kInvalidRulesRegistryID = -1;
47 RulesRegistryService::RulesRegistryService(content::BrowserContext* context)
48 : current_rules_registry_id_(kDefaultRulesRegistryID),
49 content_rules_registry_(NULL),
50 extension_registry_observer_(this),
51 browser_context_(context) {
52 if (browser_context_) {
53 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
54 EnsureDefaultRulesRegistriesRegistered(kDefaultRulesRegistryID);
58 RulesRegistryService::~RulesRegistryService() {}
60 int RulesRegistryService::GetNextRulesRegistryID() {
61 return ++current_rules_registry_id_;
64 void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered(
65 int rules_registry_id) {
66 if (!browser_context_)
67 return;
68 RulesRegistryKey key(declarative_webrequest_constants::kOnRequest,
69 rules_registry_id);
70 // If we can find the key in the |rule_registries_| then we have already
71 // installed the default registries.
72 if (ContainsKey(rule_registries_, key))
73 return;
75 // Only cache rules for regular pages.
76 RulesCacheDelegate* web_request_cache_delegate = NULL;
77 if (rules_registry_id == kDefaultRulesRegistryID) {
78 // Create a RulesCacheDelegate.
79 web_request_cache_delegate =
80 new RulesCacheDelegate(true /*log_storage_init_delay*/);
81 cache_delegates_.push_back(web_request_cache_delegate);
83 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
84 new WebRequestRulesRegistry(browser_context_, web_request_cache_delegate,
85 rules_registry_id));
87 RegisterRulesRegistry(web_request_rules_registry);
88 content::BrowserThread::PostTask(
89 content::BrowserThread::IO, FROM_HERE,
90 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
91 browser_context_, rules_registry_id,
92 web_request_rules_registry));
94 // Only create a ContentRulesRegistry for regular pages.
95 if (rules_registry_id == kDefaultRulesRegistryID) {
96 RulesCacheDelegate* content_rules_cache_delegate =
97 new RulesCacheDelegate(false /*log_storage_init_delay*/);
98 cache_delegates_.push_back(content_rules_cache_delegate);
99 scoped_refptr<ContentRulesRegistry> content_rules_registry =
100 ExtensionsAPIClient::Get()->CreateContentRulesRegistry(
101 browser_context_, content_rules_cache_delegate);
102 if (content_rules_registry.get() != nullptr) {
103 RegisterRulesRegistry(content_rules_registry);
104 content_rules_registry_ = content_rules_registry.get();
109 void RulesRegistryService::Shutdown() {
110 // Release the references to all registries. This would happen soon during
111 // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to
112 // be the last to reference the WebRequestRulesRegistry objects, so that
113 // the posted task below causes their destruction on the IO thread, not on UI
114 // where the destruction of |*this| takes place.
115 // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed.
116 rule_registries_.clear();
117 content::BrowserThread::PostTask(
118 content::BrowserThread::IO, FROM_HERE,
119 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
120 browser_context_,
121 RulesRegistryService::kDefaultRulesRegistryID,
122 scoped_refptr<WebRequestRulesRegistry>(NULL)));
125 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> >
126 g_factory = LAZY_INSTANCE_INITIALIZER;
128 // static
129 BrowserContextKeyedAPIFactory<RulesRegistryService>*
130 RulesRegistryService::GetFactoryInstance() {
131 return g_factory.Pointer();
134 // static
135 RulesRegistryService* RulesRegistryService::Get(
136 content::BrowserContext* context) {
137 return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context);
140 // static
141 RulesRegistryService* RulesRegistryService::GetIfExists(
142 content::BrowserContext* context) {
143 return BrowserContextKeyedAPIFactory<RulesRegistryService>::GetIfExists(
144 context);
147 void RulesRegistryService::RegisterRulesRegistry(
148 scoped_refptr<RulesRegistry> rule_registry) {
149 const std::string event_name(rule_registry->event_name());
150 RulesRegistryKey key(event_name, rule_registry->id());
151 DCHECK(rule_registries_.find(key) == rule_registries_.end());
152 rule_registries_[key] = rule_registry;
155 scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry(
156 int rules_registry_id,
157 const std::string& event_name) {
158 EnsureDefaultRulesRegistriesRegistered(rules_registry_id);
160 RulesRegistryKey key(event_name, rules_registry_id);
161 RulesRegistryMap::const_iterator i = rule_registries_.find(key);
162 if (i == rule_registries_.end())
163 return scoped_refptr<RulesRegistry>();
164 return i->second;
167 void RulesRegistryService::RemoveRulesRegistriesByID(int rules_registry_id) {
168 std::set<RulesRegistryKey> registries_to_delete;
169 for (RulesRegistryMap::iterator it = rule_registries_.begin();
170 it != rule_registries_.end(); ++it) {
171 const RulesRegistryKey& key = it->first;
172 if (key.rules_registry_id != rules_registry_id)
173 continue;
174 // Modifying a container while iterating over it can lead to badness. So we
175 // save the keys in another container and delete them in another loop.
176 registries_to_delete.insert(key);
179 for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin();
180 it != registries_to_delete.end(); ++it) {
181 rule_registries_.erase(*it);
185 void RulesRegistryService::SimulateExtensionUninstalled(
186 const Extension* extension) {
187 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension);
190 void RulesRegistryService::NotifyRegistriesHelper(
191 void (RulesRegistry::*notification_callback)(const Extension*),
192 const Extension* extension) {
193 RulesRegistryMap::iterator i;
194 for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) {
195 scoped_refptr<RulesRegistry> registry = i->second;
196 if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) {
197 (registry.get()->*notification_callback)(extension);
198 } else {
199 content::BrowserThread::PostTask(
200 registry->owner_thread(), FROM_HERE,
201 base::Bind(&NotifyWithExtensionSafe, make_scoped_refptr(extension),
202 notification_callback, registry));
207 void RulesRegistryService::OnExtensionLoaded(
208 content::BrowserContext* browser_context,
209 const Extension* extension) {
210 NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, extension);
213 void RulesRegistryService::OnExtensionUnloaded(
214 content::BrowserContext* browser_context,
215 const Extension* extension,
216 UnloadedExtensionInfo::Reason reason) {
217 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, extension);
220 void RulesRegistryService::OnExtensionUninstalled(
221 content::BrowserContext* browser_context,
222 const Extension* extension,
223 extensions::UninstallReason reason) {
224 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension);
227 } // namespace extensions