root/chrome/browser/extensions/api/declarative/rules_registry_service.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. RegisterToExtensionWebRequestEventRouterOnIO
  2. IsWebView
  3. profile_
  4. EnsureDefaultRulesRegistriesRegistered
  5. Shutdown
  6. GetFactoryInstance
  7. Get
  8. RegisterRulesRegistry
  9. GetRulesRegistry
  10. RemoveWebViewRulesRegistries
  11. SimulateExtensionUninstalled
  12. NotifyRegistriesHelper
  13. Observe

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"

#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/declarative/rules_cache_delegate.h"
#include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h"
#include "chrome/browser/extensions/api/web_request/web_request_api.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/common/extension.h"

namespace extensions {

namespace {

// Registers |web_request_rules_registry| on the IO thread.
void RegisterToExtensionWebRequestEventRouterOnIO(
    void* profile,
    const RulesRegistryService::WebViewKey& webview_key,
    scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) {
  ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry(
      profile, webview_key, web_request_rules_registry);
}

bool IsWebView(const RulesRegistryService::WebViewKey& webview_key) {
  return webview_key.embedder_process_id && webview_key.webview_instance_id;
}

}  // namespace

RulesRegistryService::RulesRegistryService(content::BrowserContext* context)
    : content_rules_registry_(NULL),
      profile_(Profile::FromBrowserContext(context)) {
  if (profile_) {
    registrar_.Add(this,
                   chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
                   content::Source<Profile>(profile_->GetOriginalProfile()));
    registrar_.Add(this,
                   chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
                   content::Source<Profile>(profile_->GetOriginalProfile()));
    registrar_.Add(this,
                   chrome::NOTIFICATION_EXTENSION_LOADED,
                   content::Source<Profile>(profile_->GetOriginalProfile()));
    registrar_.Add(
        this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
        content::NotificationService::AllBrowserContextsAndSources());
    EnsureDefaultRulesRegistriesRegistered(WebViewKey(0, 0));
  }
}

RulesRegistryService::~RulesRegistryService() {}

void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered(
    const WebViewKey& webview_key) {
  if (!profile_)
    return;

  RulesRegistryKey key(declarative_webrequest_constants::kOnRequest,
                       webview_key);
  // If we can find the key in the |rule_registries_| then we have already
  // installed the default registries.
  if (ContainsKey(rule_registries_, key))
    return;


  RulesCacheDelegate* web_request_cache_delegate = NULL;
  if (!IsWebView(webview_key)) {
    web_request_cache_delegate =
        new RulesCacheDelegate(true /*log_storage_init_delay*/);
    cache_delegates_.push_back(web_request_cache_delegate);
  }
  scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
      new WebRequestRulesRegistry(profile_,
                                  web_request_cache_delegate,
                                  webview_key));

  RegisterRulesRegistry(web_request_rules_registry);
  content::BrowserThread::PostTask(
      content::BrowserThread::IO, FROM_HERE,
      base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
          profile_, webview_key, web_request_rules_registry));

#if defined(ENABLE_EXTENSIONS)
  // Only create a ContentRulesRegistry for regular pages and not webviews.
  if (!IsWebView(webview_key)) {
    RulesCacheDelegate* content_rules_cache_delegate =
        new RulesCacheDelegate(false /*log_storage_init_delay*/);
    cache_delegates_.push_back(content_rules_cache_delegate);
    scoped_refptr<ContentRulesRegistry> content_rules_registry(
        new ContentRulesRegistry(profile_, content_rules_cache_delegate));
    RegisterRulesRegistry(content_rules_registry);
    content_rules_registry_ = content_rules_registry.get();
  }
#endif  // defined(ENABLE_EXTENSIONS)
}

void RulesRegistryService::Shutdown() {
  // Release the references to all registries. This would happen soon during
  // destruction of |*this|, but we need the ExtensionWebRequestEventRouter to
  // be the last to reference the WebRequestRulesRegistry objects, so that
  // the posted task below causes their destruction on the IO thread, not on UI
  // where the destruction of |*this| takes place.
  // TODO(vabr): Remove once http://crbug.com/218451#c6 gets addressed.
  rule_registries_.clear();
  content::BrowserThread::PostTask(
      content::BrowserThread::IO, FROM_HERE,
      base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
          profile_, WebViewKey(0, 0),
          scoped_refptr<WebRequestRulesRegistry>(NULL)));
}

static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> >
    g_factory = LAZY_INSTANCE_INITIALIZER;

// static
BrowserContextKeyedAPIFactory<RulesRegistryService>*
RulesRegistryService::GetFactoryInstance() {
  return g_factory.Pointer();
}

// static
RulesRegistryService* RulesRegistryService::Get(
    content::BrowserContext* context) {
  return BrowserContextKeyedAPIFactory<RulesRegistryService>::Get(context);
}

void RulesRegistryService::RegisterRulesRegistry(
    scoped_refptr<RulesRegistry> rule_registry) {
  const std::string event_name(rule_registry->event_name());
  RulesRegistryKey key(event_name, rule_registry->webview_key());
  DCHECK(rule_registries_.find(key) == rule_registries_.end());
  rule_registries_[key] = rule_registry;
}

scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry(
    const WebViewKey& webview_key,
    const std::string& event_name) {
  EnsureDefaultRulesRegistriesRegistered(webview_key);

  RulesRegistryKey key(event_name, webview_key);
  RulesRegistryMap::const_iterator i = rule_registries_.find(key);
  if (i == rule_registries_.end())
    return scoped_refptr<RulesRegistry>();
  return i->second;
}

void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) {
  DCHECK_NE(0, process_id);

  std::set<RulesRegistryKey> registries_to_delete;
  for (RulesRegistryMap::iterator it = rule_registries_.begin();
       it != rule_registries_.end(); ++it) {
    const RulesRegistryKey& key = it->first;
    const WebViewKey& webview_key = key.webview_key;
    int embedder_process_id = webview_key.embedder_process_id;
    // |process_id| will always be non-zero.
    // |embedder_process_id| will only be non-zero if the key corresponds to a
    // webview registry.
    // Thus, |embedder_process_id| == |process_id| ==> the process ID is a
    // webview embedder.
    if (embedder_process_id != process_id)
      continue;

    // Modifying the container while iterating is bad so we'll save the keys we
    // wish to delete in another container, and delete them in another loop.
    registries_to_delete.insert(key);
  }
  for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin();
       it != registries_to_delete.end(); ++it) {
    rule_registries_.erase(*it);
  }
}

void RulesRegistryService::SimulateExtensionUninstalled(
    const std::string& extension_id) {
  NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled, extension_id);
}

void RulesRegistryService::NotifyRegistriesHelper(
    void (RulesRegistry::*notification_callback)(const std::string&),
    const std::string& extension_id) {
  RulesRegistryMap::iterator i;
  for (i = rule_registries_.begin(); i != rule_registries_.end(); ++i) {
    scoped_refptr<RulesRegistry> registry = i->second;
    if (content::BrowserThread::CurrentlyOn(registry->owner_thread())) {
      (registry->*notification_callback)(extension_id);
    } else {
      content::BrowserThread::PostTask(
          registry->owner_thread(),
          FROM_HERE,
          base::Bind(notification_callback, registry, extension_id));
    }
  }
}

void RulesRegistryService::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
      const Extension* extension =
          content::Details<UnloadedExtensionInfo>(details)->extension;
      NotifyRegistriesHelper(&RulesRegistry::OnExtensionUnloaded,
                             extension->id());
      break;
    }
    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
      const Extension* extension =
          content::Details<const Extension>(details).ptr();
      NotifyRegistriesHelper(&RulesRegistry::OnExtensionUninstalled,
                             extension->id());
      break;
    }
    case chrome::NOTIFICATION_EXTENSION_LOADED: {
      const Extension* extension =
          content::Details<const Extension>(details).ptr();
      NotifyRegistriesHelper(&RulesRegistry::OnExtensionLoaded,
                             extension->id());
      break;
    }
    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
      content::RenderProcessHost* process =
          content::Source<content::RenderProcessHost>(source).ptr();
      RemoveWebViewRulesRegistries(process->GetID());
      break;
    }
    default:
      NOTREACHED();
      break;
  }
}

}  // namespace extensions

/* [<][>][^][v][top][bottom][index][help] */