Home | History | Annotate | Download | only in extensions
      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/extension_info_map.h"
      6 
      7 #include "chrome/common/extensions/extension.h"
      8 #include "chrome/common/extensions/extension_set.h"
      9 #include "chrome/common/extensions/incognito_handler.h"
     10 #include "chrome/common/url_constants.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "extensions/common/constants.h"
     13 
     14 using content::BrowserThread;
     15 using extensions::Extension;
     16 
     17 namespace {
     18 
     19 void CheckOnValidThread() {
     20   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     21 }
     22 
     23 }  // namespace
     24 
     25 struct ExtensionInfoMap::ExtraData {
     26   // When the extension was installed.
     27   base::Time install_time;
     28 
     29   // True if the user has allowed this extension to run in incognito mode.
     30   bool incognito_enabled;
     31 
     32   ExtraData();
     33   ~ExtraData();
     34 };
     35 
     36 ExtensionInfoMap::ExtraData::ExtraData() : incognito_enabled(false) {}
     37 
     38 ExtensionInfoMap::ExtraData::~ExtraData() {}
     39 
     40 ExtensionInfoMap::ExtensionInfoMap() : signin_process_id_(-1) {}
     41 
     42 const extensions::ProcessMap& ExtensionInfoMap::process_map() const {
     43   return process_map_;
     44 }
     45 
     46 void ExtensionInfoMap::AddExtension(const Extension* extension,
     47                                     base::Time install_time,
     48                                     bool incognito_enabled) {
     49   CheckOnValidThread();
     50   extensions_.Insert(extension);
     51   disabled_extensions_.Remove(extension->id());
     52 
     53   extra_data_[extension->id()].install_time = install_time;
     54   extra_data_[extension->id()].incognito_enabled = incognito_enabled;
     55 }
     56 
     57 void ExtensionInfoMap::RemoveExtension(const std::string& extension_id,
     58     const extension_misc::UnloadedExtensionReason reason) {
     59   CheckOnValidThread();
     60   const Extension* extension = extensions_.GetByID(extension_id);
     61   extra_data_.erase(extension_id);  // we don't care about disabled extra data
     62   bool was_uninstalled = (reason != extension_misc::UNLOAD_REASON_DISABLE &&
     63                           reason != extension_misc::UNLOAD_REASON_TERMINATE);
     64   if (extension) {
     65     if (!was_uninstalled)
     66       disabled_extensions_.Insert(extension);
     67     extensions_.Remove(extension_id);
     68   } else if (was_uninstalled) {
     69     // If the extension was uninstalled, make sure it's removed from the map of
     70     // disabled extensions.
     71     disabled_extensions_.Remove(extension_id);
     72   } else {
     73     // NOTE: This can currently happen if we receive multiple unload
     74     // notifications, e.g. setting incognito-enabled state for a
     75     // disabled extension (e.g., via sync).  See
     76     // http://code.google.com/p/chromium/issues/detail?id=50582 .
     77     NOTREACHED() << extension_id;
     78   }
     79 }
     80 
     81 base::Time ExtensionInfoMap::GetInstallTime(
     82     const std::string& extension_id) const {
     83   ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
     84   if (iter != extra_data_.end())
     85     return iter->second.install_time;
     86   return base::Time();
     87 }
     88 
     89 bool ExtensionInfoMap::IsIncognitoEnabled(
     90     const std::string& extension_id) const {
     91   // Keep in sync with duplicate in extension_process_manager.cc.
     92   ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
     93   if (iter != extra_data_.end())
     94     return iter->second.incognito_enabled;
     95   return false;
     96 }
     97 
     98 bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) const {
     99   // This is duplicated from ExtensionService :(.
    100   return IsIncognitoEnabled(extension->id()) &&
    101       !extensions::IncognitoInfo::IsSplitMode(extension);
    102 }
    103 
    104 void ExtensionInfoMap::RegisterExtensionProcess(const std::string& extension_id,
    105                                                 int process_id,
    106                                                 int site_instance_id) {
    107   if (!process_map_.Insert(extension_id, process_id, site_instance_id)) {
    108     NOTREACHED() << "Duplicate extension process registration for: "
    109                  << extension_id << "," << process_id << ".";
    110   }
    111 }
    112 
    113 void ExtensionInfoMap::UnregisterExtensionProcess(
    114     const std::string& extension_id,
    115     int process_id,
    116     int site_instance_id) {
    117   if (!process_map_.Remove(extension_id, process_id, site_instance_id)) {
    118     NOTREACHED() << "Unknown extension process registration for: "
    119                  << extension_id << "," << process_id << ".";
    120   }
    121 }
    122 
    123 void ExtensionInfoMap::UnregisterAllExtensionsInProcess(int process_id) {
    124   process_map_.RemoveAllFromProcess(process_id);
    125 }
    126 
    127 void ExtensionInfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin(
    128     const GURL& origin,
    129     int process_id,
    130     extensions::APIPermission::ID permission,
    131     ExtensionSet* extensions) const {
    132   DCHECK(extensions);
    133 
    134   if (origin.SchemeIs(extensions::kExtensionScheme)) {
    135     const std::string& id = origin.host();
    136     const Extension* extension = extensions_.GetByID(id);
    137     if (extension && extension->HasAPIPermission(permission) &&
    138         process_map_.Contains(id, process_id)) {
    139       extensions->Insert(extension);
    140     }
    141     return;
    142   }
    143 
    144   ExtensionSet::const_iterator i = extensions_.begin();
    145   for (; i != extensions_.end(); ++i) {
    146     if ((*i)->web_extent().MatchesSecurityOrigin(origin) &&
    147         process_map_.Contains((*i)->id(), process_id) &&
    148         (*i)->HasAPIPermission(permission)) {
    149       extensions->Insert(*i);
    150     }
    151   }
    152 }
    153 
    154 bool ExtensionInfoMap::SecurityOriginHasAPIPermission(
    155     const GURL& origin, int process_id,
    156     extensions::APIPermission::ID permission) const {
    157   ExtensionSet extensions;
    158   GetExtensionsWithAPIPermissionForSecurityOrigin(
    159       origin, process_id, permission, &extensions);
    160   return !extensions.is_empty();
    161 }
    162 
    163 ExtensionsQuotaService* ExtensionInfoMap::GetQuotaService() {
    164   CheckOnValidThread();
    165   if (!quota_service_)
    166     quota_service_.reset(new ExtensionsQuotaService());
    167   return quota_service_.get();
    168 }
    169 
    170 void ExtensionInfoMap::SetSigninProcess(int process_id) {
    171   signin_process_id_ = process_id;
    172 }
    173 
    174 bool ExtensionInfoMap::IsSigninProcess(int process_id) const {
    175   return process_id == signin_process_id_;
    176 }
    177 
    178 ExtensionInfoMap::~ExtensionInfoMap() {
    179   if (quota_service_) {
    180     BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
    181                               quota_service_.release());
    182   }
    183 }
    184