Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / declarative / rules_registry_service.cc
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.
4
5 #include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
6
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 "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/api/declarative/rules_cache_delegate.h"
13 #include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
14 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
15 #include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
16 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/common/extension.h"
25
26 namespace extensions {
27
28 namespace {
29
30 // Registers |web_request_rules_registry| on the IO thread.
31 void RegisterToExtensionWebRequestEventRouterOnIO(
32     void* profile,
33     const RulesRegistryService::WebViewKey& webview_key,
34     scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) {
35   ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
36       profile, webview_key, web_request_rules_registry);
37 }
38
39 bool IsWebView(const RulesRegistryService::WebViewKey& webview_key) {
40   return webview_key.embedder_process_id && webview_key.webview_instance_id;
41 }
42
43 }  // namespace
44
45 RulesRegistryService::RulesRegistryService(content::BrowserContext* context)
46     : content_rules_registry_(NULL),
47       extension_registry_observer_(this),
48       profile_(Profile::FromBrowserContext(context)) {
49   if (profile_) {
50     extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
51     registrar_.Add(
52         this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
53         content::NotificationService::AllBrowserContextsAndSources());
54     EnsureDefaultRulesRegistriesRegistered(WebViewKey(0, 0));
55   }
56 }
57
58 RulesRegistryService::~RulesRegistryService() {}
59
60 void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered(
61     const WebViewKey& webview_key) {
62   if (!profile_)
63     return;
64
65   RulesRegistryKey key(declarative_webrequest_constants::kOnRequest,
66                        webview_key);
67   // If we can find the key in the |rule_registries_| then we have already
68   // installed the default registries.
69   if (ContainsKey(rule_registries_, key))
70     return;
71
72
73   RulesCacheDelegate* web_request_cache_delegate = NULL;
74   if (!IsWebView(webview_key)) {
75     web_request_cache_delegate =
76         new RulesCacheDelegate(true /*log_storage_init_delay*/);
77     cache_delegates_.push_back(web_request_cache_delegate);
78   }
79   scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
80       new WebRequestRulesRegistry(profile_,
81                                   web_request_cache_delegate,
82                                   webview_key));
83
84   RegisterRulesRegistry(web_request_rules_registry);
85   content::BrowserThread::PostTask(
86       content::BrowserThread::IO, FROM_HERE,
87       base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
88           profile_, webview_key, web_request_rules_registry));
89
90   // Only create a ContentRulesRegistry for regular pages and not webviews.
91   if (!IsWebView(webview_key)) {
92     RulesCacheDelegate* content_rules_cache_delegate =
93         new RulesCacheDelegate(false /*log_storage_init_delay*/);
94     cache_delegates_.push_back(content_rules_cache_delegate);
95     scoped_refptr<ContentRulesRegistry> content_rules_registry(
96         new ContentRulesRegistry(profile_, content_rules_cache_delegate));
97     RegisterRulesRegistry(content_rules_registry);
98     content_rules_registry_ = content_rules_registry.get();
99   }
100 }
101
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           profile_, WebViewKey(0, 0),
114           scoped_refptr<WebRequestRulesRegistry>(NULL)));
115 }
116
117 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> >
118     g_factory = LAZY_INSTANCE_INITIALIZER;
119
120 // static
121 BrowserContextKeyedAPIFactory<RulesRegistryService>*
122 RulesRegistryService::GetFactoryInstance() {
123   return g_factory.Pointer();
124 }
125
126 // static
127 RulesRegistryService* RulesRegistryService::Get(
128     content::BrowserContext* context) {
129   return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context);
130 }
131
132 void RulesRegistryService::RegisterRulesRegistry(
133     scoped_refptr<RulesRegistry> rule_registry) {
134   const std::string event_name(rule_registry->event_name());
135   RulesRegistryKey key(event_name, rule_registry->webview_key());
136   DCHECK(rule_registries_.find(key) == rule_registries_.end());
137   rule_registries_[key] = rule_registry;
138 }
139
140 scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry(
141     const WebViewKey& webview_key,
142     const std::string& event_name) {
143   EnsureDefaultRulesRegistriesRegistered(webview_key);
144
145   RulesRegistryKey key(event_name, webview_key);
146   RulesRegistryMap::const_iterator i = rule_registries_.find(key);
147   if (i == rule_registries_.end())
148     return scoped_refptr<RulesRegistry>();
149   return i->second;
150 }
151
152 void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) {
153   DCHECK_NE(0, process_id);
154
155   std::set<RulesRegistryKey> registries_to_delete;
156   for (RulesRegistryMap::iterator it = rule_registries_.begin();
157        it != rule_registries_.end(); ++it) {
158     const RulesRegistryKey& key = it->first;
159     const WebViewKey& webview_key = key.webview_key;
160     int embedder_process_id = webview_key.embedder_process_id;
161     // |process_id| will always be non-zero.
162     // |embedder_process_id| will only be non-zero if the key corresponds to a
163     // webview registry.
164     // Thus, |embedder_process_id| == |process_id| ==> the process ID is a
165     // webview embedder.
166     if (embedder_process_id != process_id)
167       continue;
168
169     // Modifying the container while iterating is bad so we'll save the keys we
170     // wish to delete in another container, and delete them in another loop.
171     registries_to_delete.insert(key);
172   }
173   for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin();
174        it != registries_to_delete.end(); ++it) {
175     rule_registries_.erase(*it);
176   }
177 }
178
179 void RulesRegistryService::SimulateExtensionUninstalled(
180     const std::string& extension_id) {
181   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id);
182 }
183
184 void RulesRegistryService::NotifyRegistriesHelper(
185     void (RulesRegistry::*notification_callback)(const std::string&),
186     const std::string& extension_id) {
187   RulesRegistryMap::iterator i;
188   for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) {
189     scoped_refptr<RulesRegistry> registry = i->second;
190     if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) {
191       (registry->*notification_callback)(extension_id);
192     } else {
193       content::BrowserThread::PostTask(
194           registry->owner_thread(),
195           FROM_HERE,
196           base::Bind(notification_callback, registry, extension_id));
197     }
198   }
199 }
200
201 void RulesRegistryService::OnExtensionLoaded(
202     content::BrowserContext* browser_context,
203     const Extension* extension) {
204   NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, extension->id());
205 }
206
207 void RulesRegistryService::OnExtensionUnloaded(
208     content::BrowserContext* browser_context,
209     const Extension* extension,
210     UnloadedExtensionInfo::Reason reason) {
211   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, extension->id());
212 }
213
214 void RulesRegistryService::OnExtensionUninstalled(
215     content::BrowserContext* browser_context,
216     const Extension* extension,
217     extensions::UninstallReason reason) {
218   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled,
219                          extension->id());
220 }
221
222 void RulesRegistryService::Observe(
223     int type,
224     const content::NotificationSource& source,
225     const content::NotificationDetails& details) {
226   DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type);
227
228   content::RenderProcessHost* process =
229       content::Source<content::RenderProcessHost>(source).ptr();
230   RemoveWebViewRulesRegistries(process->GetID());
231 }
232
233 }  // namespace extensions