Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / extensions / browser / api / declarative / rules_registry_service.cc
bloba1e02d840c8d77a2c4fd239a78adb17b188bbb06
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 } // namespace
37 const int RulesRegistryService::kDefaultRulesRegistryID = 0;
38 const int RulesRegistryService::kInvalidRulesRegistryID = -1;
40 RulesRegistryService::RulesRegistryService(content::BrowserContext* context)
41 : current_rules_registry_id_(kDefaultRulesRegistryID),
42 content_rules_registry_(NULL),
43 extension_registry_observer_(this),
44 browser_context_(context) {
45 if (browser_context_) {
46 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
47 EnsureDefaultRulesRegistriesRegistered(kDefaultRulesRegistryID);
51 RulesRegistryService::~RulesRegistryService() {}
53 int RulesRegistryService::GetNextRulesRegistryID() {
54 return ++current_rules_registry_id_;
57 void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered(
58 int rules_registry_id) {
59 if (!browser_context_)
60 return;
61 RulesRegistryKey key(declarative_webrequest_constants::kOnRequest,
62 rules_registry_id);
63 // If we can find the key in the |rule_registries_| then we have already
64 // installed the default registries.
65 if (ContainsKey(rule_registries_, key))
66 return;
68 // Only cache rules for regular pages.
69 RulesCacheDelegate* web_request_cache_delegate = NULL;
70 if (rules_registry_id == kDefaultRulesRegistryID) {
71 // Create a RulesCacheDelegate.
72 web_request_cache_delegate =
73 new RulesCacheDelegate(true /*log_storage_init_delay*/);
74 cache_delegates_.push_back(web_request_cache_delegate);
76 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
77 new WebRequestRulesRegistry(browser_context_, web_request_cache_delegate,
78 rules_registry_id));
80 RegisterRulesRegistry(web_request_rules_registry);
81 content::BrowserThread::PostTask(
82 content::BrowserThread::IO, FROM_HERE,
83 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
84 browser_context_, rules_registry_id,
85 web_request_rules_registry));
87 // Only create a ContentRulesRegistry for regular pages.
88 if (rules_registry_id == kDefaultRulesRegistryID) {
89 RulesCacheDelegate* content_rules_cache_delegate =
90 new RulesCacheDelegate(false /*log_storage_init_delay*/);
91 cache_delegates_.push_back(content_rules_cache_delegate);
92 scoped_refptr<ContentRulesRegistry> content_rules_registry =
93 ExtensionsAPIClient::Get()->CreateContentRulesRegistry(
94 browser_context_, content_rules_cache_delegate);
95 if (content_rules_registry.get() != nullptr) {
96 RegisterRulesRegistry(content_rules_registry);
97 content_rules_registry_ = content_rules_registry.get();
102 void RulesRegistryService::Shutdown() {
103 // Release the references to all registries. This would happen soon during
104 // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to
105 // be the last to reference the WebRequestRulesRegistry objects, so that
106 // the posted task below causes their destruction on the IO thread, not on UI
107 // where the destruction of |*this| takes place.
108 // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed.
109 rule_registries_.clear();
110 content::BrowserThread::PostTask(
111 content::BrowserThread::IO, FROM_HERE,
112 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
113 browser_context_,
114 RulesRegistryService::kDefaultRulesRegistryID,
115 scoped_refptr<WebRequestRulesRegistry>(NULL)));
118 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> >
119 g_factory = LAZY_INSTANCE_INITIALIZER;
121 // static
122 BrowserContextKeyedAPIFactory<RulesRegistryService>*
123 RulesRegistryService::GetFactoryInstance() {
124 return g_factory.Pointer();
127 // static
128 RulesRegistryService* RulesRegistryService::Get(
129 content::BrowserContext* context) {
130 return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context);
133 void RulesRegistryService::RegisterRulesRegistry(
134 scoped_refptr<RulesRegistry> rule_registry) {
135 const std::string event_name(rule_registry->event_name());
136 RulesRegistryKey key(event_name, rule_registry->id());
137 DCHECK(rule_registries_.find(key) == rule_registries_.end());
138 rule_registries_[key] = rule_registry;
141 scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry(
142 int rules_registry_id,
143 const std::string& event_name) {
144 EnsureDefaultRulesRegistriesRegistered(rules_registry_id);
146 RulesRegistryKey key(event_name, rules_registry_id);
147 RulesRegistryMap::const_iterator i = rule_registries_.find(key);
148 if (i == rule_registries_.end())
149 return scoped_refptr<RulesRegistry>();
150 return i->second;
153 void RulesRegistryService::RemoveRulesRegistriesByID(int rules_registry_id) {
154 std::set<RulesRegistryKey> registries_to_delete;
155 for (RulesRegistryMap::iterator it = rule_registries_.begin();
156 it != rule_registries_.end(); ++it) {
157 const RulesRegistryKey& key = it->first;
158 if (key.rules_registry_id != rules_registry_id)
159 continue;
160 // Modifying a container while iterating over it can lead to badness. So we
161 // save the keys in another container and delete them in another loop.
162 registries_to_delete.insert(key);
165 for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin();
166 it != registries_to_delete.end(); ++it) {
167 rule_registries_.erase(*it);
171 void RulesRegistryService::SimulateExtensionUninstalled(
172 const std::string& extension_id) {
173 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id);
176 void RulesRegistryService::NotifyRegistriesHelper(
177 void (RulesRegistry::*notification_callback)(const std::string&),
178 const std::string& extension_id) {
179 RulesRegistryMap::iterator i;
180 for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) {
181 scoped_refptr<RulesRegistry> registry = i->second;
182 if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) {
183 (registry.get()->*notification_callback)(extension_id);
184 } else {
185 content::BrowserThread::PostTask(
186 registry->owner_thread(),
187 FROM_HERE,
188 base::Bind(notification_callback, registry, extension_id));
193 void RulesRegistryService::OnExtensionLoaded(
194 content::BrowserContext* browser_context,
195 const Extension* extension) {
196 NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, extension->id());
199 void RulesRegistryService::OnExtensionUnloaded(
200 content::BrowserContext* browser_context,
201 const Extension* extension,
202 UnloadedExtensionInfo::Reason reason) {
203 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, extension->id());
206 void RulesRegistryService::OnExtensionUninstalled(
207 content::BrowserContext* browser_context,
208 const Extension* extension,
209 extensions::UninstallReason reason) {
210 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled,
211 extension->id());
214 } // namespace extensions