Home | History | Annotate | Download | only in declarative
      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 #if defined(ENABLE_EXTENSIONS)
     91   // Only create a ContentRulesRegistry for regular pages and not webviews.
     92   if (!IsWebView(webview_key)) {
     93     RulesCacheDelegate* content_rules_cache_delegate =
     94         new RulesCacheDelegate(false /*log_storage_init_delay*/);
     95     cache_delegates_.push_back(content_rules_cache_delegate);
     96     scoped_refptr<ContentRulesRegistry> content_rules_registry(
     97         new ContentRulesRegistry(profile_, content_rules_cache_delegate));
     98     RegisterRulesRegistry(content_rules_registry);
     99     content_rules_registry_ = content_rules_registry.get();
    100   }
    101 #endif  // defined(ENABLE_EXTENSIONS)
    102 }
    103 
    104 void RulesRegistryService::Shutdown() {
    105   // Release the references to all registries. This would happen soon during
    106   // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to
    107   // be the last to reference the WebRequestRulesRegistry objects, so that
    108   // the posted task below causes their destruction on the IO thread, not on UI
    109   // where the destruction of |*this| takes place.
    110   // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed.
    111   rule_registries_.clear();
    112   content::BrowserThread::PostTask(
    113       content::BrowserThread::IO, FROM_HERE,
    114       base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
    115           profile_, WebViewKey(0, 0),
    116           scoped_refptr<WebRequestRulesRegistry>(NULL)));
    117 }
    118 
    119 static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> >
    120     g_factory = LAZY_INSTANCE_INITIALIZER;
    121 
    122 // static
    123 BrowserContextKeyedAPIFactory<RulesRegistryService>*
    124 RulesRegistryService::GetFactoryInstance() {
    125   return g_factory.Pointer();
    126 }
    127 
    128 // static
    129 RulesRegistryService* RulesRegistryService::Get(
    130     content::BrowserContext* context) {
    131   return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context);
    132 }
    133 
    134 void RulesRegistryService::RegisterRulesRegistry(
    135     scoped_refptr<RulesRegistry> rule_registry) {
    136   const std::string event_name(rule_registry->event_name());
    137   RulesRegistryKey key(event_name, rule_registry->webview_key());
    138   DCHECK(rule_registries_.find(key) == rule_registries_.end());
    139   rule_registries_[key] = rule_registry;
    140 }
    141 
    142 scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry(
    143     const WebViewKey& webview_key,
    144     const std::string& event_name) {
    145   EnsureDefaultRulesRegistriesRegistered(webview_key);
    146 
    147   RulesRegistryKey key(event_name, webview_key);
    148   RulesRegistryMap::const_iterator i = rule_registries_.find(key);
    149   if (i == rule_registries_.end())
    150     return scoped_refptr<RulesRegistry>();
    151   return i->second;
    152 }
    153 
    154 void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) {
    155   DCHECK_NE(0, process_id);
    156 
    157   std::set<RulesRegistryKey> registries_to_delete;
    158   for (RulesRegistryMap::iterator it = rule_registries_.begin();
    159        it != rule_registries_.end(); ++it) {
    160     const RulesRegistryKey& key = it->first;
    161     const WebViewKey& webview_key = key.webview_key;
    162     int embedder_process_id = webview_key.embedder_process_id;
    163     // |process_id| will always be non-zero.
    164     // |embedder_process_id| will only be non-zero if the key corresponds to a
    165     // webview registry.
    166     // Thus, |embedder_process_id| == |process_id| ==> the process ID is a
    167     // webview embedder.
    168     if (embedder_process_id != process_id)
    169       continue;
    170 
    171     // Modifying the container while iterating is bad so we'll save the keys we
    172     // wish to delete in another container, and delete them in another loop.
    173     registries_to_delete.insert(key);
    174   }
    175   for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin();
    176        it != registries_to_delete.end(); ++it) {
    177     rule_registries_.erase(*it);
    178   }
    179 }
    180 
    181 void RulesRegistryService::SimulateExtensionUninstalled(
    182     const std::string& extension_id) {
    183   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id);
    184 }
    185 
    186 void RulesRegistryService::NotifyRegistriesHelper(
    187     void (RulesRegistry::*notification_callback)(const std::string&),
    188     const std::string& extension_id) {
    189   RulesRegistryMap::iterator i;
    190   for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) {
    191     scoped_refptr<RulesRegistry> registry = i->second;
    192     if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) {
    193       (registry->*notification_callback)(extension_id);
    194     } else {
    195       content::BrowserThread::PostTask(
    196           registry->owner_thread(),
    197           FROM_HERE,
    198           base::Bind(notification_callback, registry, extension_id));
    199     }
    200   }
    201 }
    202 
    203 void RulesRegistryService::OnExtensionLoaded(
    204     content::BrowserContext* browser_context,
    205     const Extension* extension) {
    206   NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded, extension->id());
    207 }
    208 
    209 void RulesRegistryService::OnExtensionUnloaded(
    210     content::BrowserContext* browser_context,
    211     const Extension* extension,
    212     UnloadedExtensionInfo::Reason reason) {
    213   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded, extension->id());
    214 }
    215 
    216 void RulesRegistryService::OnExtensionUninstalled(
    217     content::BrowserContext* browser_context,
    218     const Extension* extension) {
    219   NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled,
    220                          extension->id());
    221 }
    222 
    223 void 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