1 // Copyright 2013 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/info_map.h" 6 7 #include "chrome/common/extensions/extension_set.h" 8 #include "content/public/browser/browser_thread.h" 9 #include "extensions/common/constants.h" 10 #include "extensions/common/extension.h" 11 #include "extensions/common/manifest_handlers/incognito_info.h" 12 13 using content::BrowserThread; 14 15 namespace extensions { 16 17 namespace { 18 19 void CheckOnValidThread() { 20 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 21 } 22 23 } // namespace 24 25 struct InfoMap::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 // True if the user has disabled notifications for this extension manually. 33 bool notifications_disabled; 34 35 ExtraData(); 36 ~ExtraData(); 37 }; 38 39 InfoMap::ExtraData::ExtraData() : incognito_enabled(false) {} 40 41 InfoMap::ExtraData::~ExtraData() {} 42 43 InfoMap::InfoMap() : signin_process_id_(-1) {} 44 45 const ProcessMap& InfoMap::process_map() const { return process_map_; } 46 47 void InfoMap::AddExtension(const Extension* extension, 48 base::Time install_time, 49 bool incognito_enabled, 50 bool notifications_disabled) { 51 CheckOnValidThread(); 52 extensions_.Insert(extension); 53 disabled_extensions_.Remove(extension->id()); 54 55 extra_data_[extension->id()].install_time = install_time; 56 extra_data_[extension->id()].incognito_enabled = incognito_enabled; 57 extra_data_[extension->id()].notifications_disabled = notifications_disabled; 58 } 59 60 void InfoMap::RemoveExtension(const std::string& extension_id, 61 const UnloadedExtensionInfo::Reason reason) { 62 CheckOnValidThread(); 63 const Extension* extension = extensions_.GetByID(extension_id); 64 extra_data_.erase(extension_id); // we don't care about disabled extra data 65 bool was_uninstalled = (reason != UnloadedExtensionInfo::REASON_DISABLE && 66 reason != UnloadedExtensionInfo::REASON_TERMINATE); 67 if (extension) { 68 if (!was_uninstalled) 69 disabled_extensions_.Insert(extension); 70 extensions_.Remove(extension_id); 71 } else if (was_uninstalled) { 72 // If the extension was uninstalled, make sure it's removed from the map of 73 // disabled extensions. 74 disabled_extensions_.Remove(extension_id); 75 } else { 76 // NOTE: This can currently happen if we receive multiple unload 77 // notifications, e.g. setting incognito-enabled state for a 78 // disabled extension (e.g., via sync). See 79 // http://code.google.com/p/chromium/issues/detail?id=50582 . 80 NOTREACHED() << extension_id; 81 } 82 } 83 84 base::Time InfoMap::GetInstallTime(const std::string& extension_id) const { 85 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 86 if (iter != extra_data_.end()) 87 return iter->second.install_time; 88 return base::Time(); 89 } 90 91 bool InfoMap::IsIncognitoEnabled(const std::string& extension_id) const { 92 // Keep in sync with duplicate in extensions/browser/process_manager.cc. 93 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 94 if (iter != extra_data_.end()) 95 return iter->second.incognito_enabled; 96 return false; 97 } 98 99 bool InfoMap::CanCrossIncognito(const Extension* extension) const { 100 // This is duplicated from ExtensionService :(. 101 return IsIncognitoEnabled(extension->id()) && 102 !IncognitoInfo::IsSplitMode(extension); 103 } 104 105 void InfoMap::RegisterExtensionProcess(const std::string& extension_id, 106 int process_id, 107 int site_instance_id) { 108 if (!process_map_.Insert(extension_id, process_id, site_instance_id)) { 109 NOTREACHED() << "Duplicate extension process registration for: " 110 << extension_id << "," << process_id << "."; 111 } 112 } 113 114 void InfoMap::UnregisterExtensionProcess(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 InfoMap::UnregisterAllExtensionsInProcess(int process_id) { 124 process_map_.RemoveAllFromProcess(process_id); 125 } 126 127 void InfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin( 128 const GURL& origin, 129 int process_id, 130 APIPermission::ID permission, 131 ExtensionSet* extensions) const { 132 DCHECK(extensions); 133 134 if (origin.SchemeIs(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 InfoMap::SecurityOriginHasAPIPermission(const GURL& origin, 155 int process_id, 156 APIPermission::ID permission) 157 const { 158 ExtensionSet extensions; 159 GetExtensionsWithAPIPermissionForSecurityOrigin( 160 origin, process_id, permission, &extensions); 161 return !extensions.is_empty(); 162 } 163 164 QuotaService* InfoMap::GetQuotaService() { 165 CheckOnValidThread(); 166 if (!quota_service_) 167 quota_service_.reset(new QuotaService()); 168 return quota_service_.get(); 169 } 170 171 void InfoMap::SetSigninProcess(int process_id) { 172 signin_process_id_ = process_id; 173 } 174 175 bool InfoMap::IsSigninProcess(int process_id) const { 176 return process_id == signin_process_id_; 177 } 178 179 void InfoMap::SetNotificationsDisabled( 180 const std::string& extension_id, 181 bool notifications_disabled) { 182 ExtraDataMap::iterator iter = extra_data_.find(extension_id); 183 if (iter != extra_data_.end()) 184 iter->second.notifications_disabled = notifications_disabled; 185 } 186 187 bool InfoMap::AreNotificationsDisabled( 188 const std::string& extension_id) const { 189 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 190 if (iter != extra_data_.end()) 191 return iter->second.notifications_disabled; 192 return false; 193 } 194 195 InfoMap::~InfoMap() { 196 if (quota_service_) { 197 BrowserThread::DeleteSoon( 198 BrowserThread::IO, FROM_HERE, quota_service_.release()); 199 } 200 } 201 202 } // namespace extensions 203