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 "content/public/browser/browser_thread.h" 18 #include "content/public/browser/notification_details.h" 19 #include "content/public/browser/notification_service.h" 20 #include "content/public/browser/notification_source.h" 21 #include "content/public/browser/render_process_host.h" 22 #include "extensions/common/extension.h" 23 24 namespace extensions { 25 26 namespace { 27 28 // Registers |web_request_rules_registry| on the IO thread. 29 void RegisterToExtensionWebRequestEventRouterOnIO( 30 void* profile, 31 const RulesRegistryService::WebViewKey& webview_key, 32 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) { 33 ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry( 34 profile, webview_key, web_request_rules_registry); 35 } 36 37 bool IsWebView(const RulesRegistryService::WebViewKey& webview_key) { 38 return webview_key.embedder_process_id && webview_key.webview_instance_id; 39 } 40 41 } // namespace 42 43 RulesRegistryService::RulesRegistryService(Profile* profile) 44 : content_rules_registry_(NULL), 45 profile_(profile) { 46 if (profile) { 47 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 48 content::Source<Profile>(profile->GetOriginalProfile())); 49 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 50 content::Source<Profile>(profile->GetOriginalProfile())); 51 registrar_.Add(this, 52 chrome::NOTIFICATION_EXTENSION_LOADED, 53 content::Source<Profile>(profile_->GetOriginalProfile())); 54 registrar_.Add( 55 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 56 content::NotificationService::AllBrowserContextsAndSources()); 57 EnsureDefaultRulesRegistriesRegistered(WebViewKey(0, 0)); 58 } 59 } 60 61 RulesRegistryService::~RulesRegistryService() {} 62 63 void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered( 64 const WebViewKey& webview_key) { 65 if (!profile_) 66 return; 67 68 RulesRegistryKey key(declarative_webrequest_constants::kOnRequest, 69 webview_key); 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; 74 75 76 RulesCacheDelegate* web_request_cache_delegate = NULL; 77 if (!IsWebView(webview_key)) { 78 web_request_cache_delegate = 79 new RulesCacheDelegate(true /*log_storage_init_delay*/); 80 cache_delegates_.push_back(web_request_cache_delegate); 81 } 82 scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry( 83 new WebRequestRulesRegistry(profile_, 84 web_request_cache_delegate, 85 webview_key)); 86 87 RegisterRulesRegistry(web_request_rules_registry); 88 content::BrowserThread::PostTask( 89 content::BrowserThread::IO, FROM_HERE, 90 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, 91 profile_, webview_key, web_request_rules_registry)); 92 93 #if defined(ENABLE_EXTENSIONS) 94 // Only create a ContentRulesRegistry for regular pages and not webviews. 95 if (!IsWebView(webview_key)) { 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 new ContentRulesRegistry(profile_, content_rules_cache_delegate)); 101 RegisterRulesRegistry(content_rules_registry); 102 content_rules_registry_ = content_rules_registry.get(); 103 } 104 #endif // defined(ENABLE_EXTENSIONS) 105 } 106 107 void RulesRegistryService::Shutdown() { 108 // Release the references to all registries. This would happen soon during 109 // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to 110 // be the last to reference the WebRequestRulesRegistry objects, so that 111 // the posted task below causes their destruction on the IO thread, not on UI 112 // where the destruction of |*this| takes place. 113 // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed. 114 rule_registries_.clear(); 115 content::BrowserThread::PostTask( 116 content::BrowserThread::IO, FROM_HERE, 117 base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, 118 profile_, WebViewKey(0, 0), 119 scoped_refptr<WebRequestRulesRegistry>(NULL))); 120 } 121 122 static base::LazyInstance<ProfileKeyedAPIFactory<RulesRegistryService> > 123 g_factory = LAZY_INSTANCE_INITIALIZER; 124 125 // static 126 ProfileKeyedAPIFactory<RulesRegistryService>* 127 RulesRegistryService::GetFactoryInstance() { 128 return &g_factory.Get(); 129 } 130 131 // static 132 RulesRegistryService* RulesRegistryService::Get(Profile* profile) { 133 return ProfileKeyedAPIFactory<RulesRegistryService>::GetForProfile(profile); 134 } 135 136 void RulesRegistryService::RegisterRulesRegistry( 137 scoped_refptr<RulesRegistry> rule_registry) { 138 const std::string event_name(rule_registry->event_name()); 139 RulesRegistryKey key(event_name, rule_registry->webview_key()); 140 DCHECK(rule_registries_.find(key) == rule_registries_.end()); 141 rule_registries_[key] = rule_registry; 142 } 143 144 scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry( 145 const WebViewKey& webview_key, 146 const std::string& event_name) { 147 EnsureDefaultRulesRegistriesRegistered(webview_key); 148 149 RulesRegistryKey key(event_name, webview_key); 150 RulesRegistryMap::const_iterator i = rule_registries_.find(key); 151 if (i == rule_registries_.end()) 152 return scoped_refptr<RulesRegistry>(); 153 return i->second; 154 } 155 156 void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) { 157 DCHECK_NE(0, process_id); 158 159 std::set<RulesRegistryKey> registries_to_delete; 160 for (RulesRegistryMap::iterator it = rule_registries_.begin(); 161 it != rule_registries_.end(); ++it) { 162 const RulesRegistryKey& key = it->first; 163 const WebViewKey& webview_key = key.webview_key; 164 int embedder_process_id = webview_key.embedder_process_id; 165 // |process_id| will always be non-zero. 166 // |embedder_process_id| will only be non-zero if the key corresponds to a 167 // webview registry. 168 // Thus, |embedder_process_id| == |process_id| ==> the process ID is a 169 // webview embedder. 170 if (embedder_process_id != process_id) 171 continue; 172 173 // Modifying the container while iterating is bad so we'll save the keys we 174 // wish to delete in another container, and delete them in another loop. 175 registries_to_delete.insert(key); 176 } 177 for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin(); 178 it != registries_to_delete.end(); ++it) { 179 rule_registries_.erase(*it); 180 } 181 } 182 183 void RulesRegistryService::SimulateExtensionUninstalled( 184 const std::string& extension_id) { 185 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id); 186 } 187 188 void RulesRegistryService::NotifyRegistriesHelper( 189 void (RulesRegistry::*notification_callback)(const std::string&), 190 const std::string& extension_id) { 191 RulesRegistryMap::iterator i; 192 for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) { 193 scoped_refptr<RulesRegistry> registry = i->second; 194 if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) { 195 (registry->*notification_callback)(extension_id); 196 } else { 197 content::BrowserThread::PostTask( 198 registry->owner_thread(), 199 FROM_HERE, 200 base::Bind(notification_callback, registry, extension_id)); 201 } 202 } 203 } 204 205 void RulesRegistryService::Observe( 206 int type, 207 const content::NotificationSource& source, 208 const content::NotificationDetails& details) { 209 switch (type) { 210 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { 211 const Extension* extension = 212 content::Details<UnloadedExtensionInfo>(details)->extension; 213 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, 214 extension->id()); 215 break; 216 } 217 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { 218 const Extension* extension = 219 content::Details<const Extension>(details).ptr(); 220 NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, 221 extension->id()); 222 break; 223 } 224 case chrome::NOTIFICATION_EXTENSION_LOADED: { 225 const Extension* extension = 226 content::Details<const Extension>(details).ptr(); 227 NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, 228 extension->id()); 229 break; 230 } 231 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { 232 content::RenderProcessHost* process = 233 content::Source<content::RenderProcessHost>(source).ptr(); 234 RemoveWebViewRulesRegistries(process->GetID()); 235 break; 236 } 237 default: 238 NOTREACHED(); 239 break; 240 } 241 } 242 243 } // namespace extensions 244