rules_registry_service.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "extensions/browser/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 "content/public/browser/browser_thread.h" 12#include "content/public/browser/notification_details.h" 13#include "content/public/browser/notification_service.h" 14#include "content/public/browser/notification_source.h" 15#include "content/public/browser/notification_types.h" 16#include "content/public/browser/render_process_host.h" 17#include "extensions/browser/api/declarative/rules_cache_delegate.h" 18#include "extensions/browser/api/declarative_content/content_rules_registry.h" 19#include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" 20#include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h" 21#include "extensions/browser/api/extensions_api_client.h" 22#include "extensions/browser/api/web_request/web_request_api.h" 23#include "extensions/browser/extension_registry.h" 24#include "extensions/common/extension.h" 25 26namespace extensions { 27 28namespace { 29 30// Registers |web_request_rules_registry| on the IO thread. 31void RegisterToExtensionWebRequestEventRouterOnIO( 32 content::BrowserContext* browser_context, 33 const RulesRegistryService::WebViewKey& webview_key, 34 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) { 35 ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry( 36 browser_context, webview_key, web_request_rules_registry); 37} 38 39bool IsWebView(const RulesRegistryService::WebViewKey& webview_key) { 40 return webview_key.embedder_process_id && webview_key.webview_instance_id; 41} 42 43} // namespace 44 45RulesRegistryService::RulesRegistryService(content::BrowserContext* context) 46 : content_rules_registry_(NULL), 47 extension_registry_observer_(this), 48 browser_context_(context) { 49 if (browser_context_) { 50 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 51 registrar_.Add( 52 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 53 content::NotificationService::AllBrowserContextsAndSources()); 54 EnsureDefaultRulesRegistriesRegistered(WebViewKey(0, 0)); 55 } 56} 57 58RulesRegistryService::~RulesRegistryService() {} 59 60void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered( 61 const WebViewKey& webview_key) { 62 if (!browser_context_) 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(browser_context_, 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 browser_context_, 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 ExtensionsAPIClient::Get()->CreateContentRulesRegistry( 97 browser_context_, content_rules_cache_delegate); 98 RegisterRulesRegistry(content_rules_registry); 99 content_rules_registry_ = content_rules_registry.get(); 100 } 101} 102 103void RulesRegistryService::Shutdown() { 104 // Release the references to all registries. This would happen soon during 105 // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to 106 // be the last to reference the WebRequestRulesRegistry objects, so that 107 // the posted task below causes their destruction on the IO thread, not on UI 108 // where the destruction of |*this| takes place. 109 // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed. 110 rule_registries_.clear(); 111 content::BrowserThread::PostTask( 112 content::BrowserThread::IO, FROM_HERE, 113 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, 114 browser_context_, WebViewKey(0, 0), 115 scoped_refptr<WebRequestRulesRegistry>(NULL))); 116} 117 118static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> > 119 g_factory = LAZY_INSTANCE_INITIALIZER; 120 121// static 122BrowserContextKeyedAPIFactory<RulesRegistryService>* 123RulesRegistryService::GetFactoryInstance() { 124 return g_factory.Pointer(); 125} 126 127// static 128RulesRegistryService* RulesRegistryService::Get( 129 content::BrowserContext* context) { 130 return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context); 131} 132 133void 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->webview_key()); 137 DCHECK(rule_registries_.find(key) == rule_registries_.end()); 138 rule_registries_[key] = rule_registry; 139} 140 141scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry( 142 const WebViewKey& webview_key, 143 const std::string& event_name) { 144 EnsureDefaultRulesRegistriesRegistered(webview_key); 145 146 RulesRegistryKey key(event_name, webview_key); 147 RulesRegistryMap::const_iterator i = rule_registries_.find(key); 148 if (i == rule_registries_.end()) 149 return scoped_refptr<RulesRegistry>(); 150 return i->second; 151} 152 153void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) { 154 DCHECK_NE(0, process_id); 155 156 std::set<RulesRegistryKey> registries_to_delete; 157 for (RulesRegistryMap::iterator it = rule_registries_.begin(); 158 it != rule_registries_.end(); ++it) { 159 const RulesRegistryKey& key = it->first; 160 const WebViewKey& webview_key = key.webview_key; 161 int embedder_process_id = webview_key.embedder_process_id; 162 // |process_id| will always be non-zero. 163 // |embedder_process_id| will only be non-zero if the key corresponds to a 164 // webview registry. 165 // Thus, |embedder_process_id| == |process_id| ==> the process ID is a 166 // webview embedder. 167 if (embedder_process_id != process_id) 168 continue; 169 170 // Modifying the container while iterating is bad so we'll save the keys we 171 // wish to delete in another container, and delete them in another loop. 172 registries_to_delete.insert(key); 173 } 174 for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin(); 175 it != registries_to_delete.end(); ++it) { 176 rule_registries_.erase(*it); 177 } 178} 179 180void RulesRegistryService::SimulateExtensionUninstalled( 181 const std::string& extension_id) { 182 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id); 183} 184 185void RulesRegistryService::NotifyRegistriesHelper( 186 void (RulesRegistry::*notification_callback)(const std::string&), 187 const std::string& extension_id) { 188 RulesRegistryMap::iterator i; 189 for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) { 190 scoped_refptr<RulesRegistry> registry = i->second; 191 if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) { 192 (registry.get()->*notification_callback)(extension_id); 193 } else { 194 content::BrowserThread::PostTask( 195 registry->owner_thread(), 196 FROM_HERE, 197 base::Bind(notification_callback, registry, extension_id)); 198 } 199 } 200} 201 202void RulesRegistryService::OnExtensionLoaded( 203 content::BrowserContext* browser_context, 204 const Extension* extension) { 205 NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, extension->id()); 206} 207 208void RulesRegistryService::OnExtensionUnloaded( 209 content::BrowserContext* browser_context, 210 const Extension* extension, 211 UnloadedExtensionInfo::Reason reason) { 212 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, extension->id()); 213} 214 215void RulesRegistryService::OnExtensionUninstalled( 216 content::BrowserContext* browser_context, 217 const Extension* extension, 218 extensions::UninstallReason reason) { 219 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, 220 extension->id()); 221} 222 223void RulesRegistryService::Observe( 224 int type, 225 const content::NotificationSource& source, 226 const content::NotificationDetails& details) { 227 DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type); 228 229 content::RenderProcessHost* process = 230 content::Source<content::RenderProcessHost>(source).ptr(); 231 RemoveWebViewRulesRegistries(process->GetID()); 232} 233 234} // namespace extensions 235