Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / extensions / extension_special_storage_policy.cc
blob3ee4aef2f3936f96c5d9faeac61c3fd5bd90a5f9
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.
5 #include "chrome/browser/extensions/extension_special_storage_policy.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/content_settings/cookie_settings.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
17 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
18 #include "chrome/common/url_constants.h"
19 #include "components/content_settings/core/common/content_settings.h"
20 #include "components/content_settings/core/common/content_settings_types.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/common/url_constants.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_set.h"
28 #include "extensions/common/permissions/permissions_data.h"
29 #include "storage/browser/quota/quota_manager.h"
30 #include "storage/common/quota/quota_status_code.h"
31 #include "storage/common/quota/quota_types.h"
33 using content::BrowserThread;
34 using extensions::APIPermission;
35 using extensions::Extension;
36 using storage::SpecialStoragePolicy;
38 namespace {
40 void ReportQuotaUsage(storage::QuotaStatusCode code, int64 usage, int64 quota) {
41 if (code == storage::kQuotaStatusOk) {
42 // We're interested in the amount of space hosted apps are using. Record it
43 // when the extension is granted the unlimited storage permission (once per
44 // extension load, so on average once per run).
45 UMA_HISTOGRAM_MEMORY_KB("Extensions.HostedAppUnlimitedStorageUsage", usage);
49 // Log the usage for a hosted app with unlimited storage.
50 void LogHostedAppUnlimitedStorageUsage(
51 scoped_refptr<const Extension> extension,
52 content::BrowserContext* browser_context) {
53 GURL launch_url =
54 extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()).GetOrigin();
55 content::StoragePartition* partition =
56 browser_context ? // |browser_context| can be NULL in unittests.
57 content::BrowserContext::GetStoragePartitionForSite(browser_context,
58 launch_url) :
59 NULL;
60 if (partition) {
61 // We only have to query for kStorageTypePersistent data usage, because apps
62 // cannot ask for any more temporary storage, according to
63 // https://developers.google.com/chrome/whitepapers/storage.
64 BrowserThread::PostTask(
65 BrowserThread::IO,
66 FROM_HERE,
67 base::Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
68 partition->GetQuotaManager(),
69 launch_url,
70 storage::kStorageTypePersistent,
71 base::Bind(&ReportQuotaUsage)));
75 } // namespace
77 ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy(
78 CookieSettings* cookie_settings)
79 : cookie_settings_(cookie_settings) {}
81 ExtensionSpecialStoragePolicy::~ExtensionSpecialStoragePolicy() {}
83 bool ExtensionSpecialStoragePolicy::IsStorageProtected(const GURL& origin) {
84 if (origin.SchemeIs(extensions::kExtensionScheme))
85 return true;
86 base::AutoLock locker(lock_);
87 return protected_apps_.Contains(origin);
90 bool ExtensionSpecialStoragePolicy::IsStorageUnlimited(const GURL& origin) {
91 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUnlimitedStorage))
92 return true;
94 if (origin.SchemeIs(content::kChromeDevToolsScheme) &&
95 origin.host() == chrome::kChromeUIDevToolsHost)
96 return true;
98 base::AutoLock locker(lock_);
99 return unlimited_extensions_.Contains(origin);
102 bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) {
103 if (cookie_settings_.get() == NULL)
104 return false;
105 return cookie_settings_->IsCookieSessionOnly(origin);
108 bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) {
109 return installed_apps_.Contains(origin);
112 bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
113 if (cookie_settings_.get() == NULL)
114 return false;
115 if (cookie_settings_->GetDefaultCookieSetting(NULL) ==
116 CONTENT_SETTING_SESSION_ONLY)
117 return true;
118 ContentSettingsForOneType entries;
119 cookie_settings_->GetCookieSettings(&entries);
120 for (size_t i = 0; i < entries.size(); ++i) {
121 if (entries[i].setting == CONTENT_SETTING_SESSION_ONLY)
122 return true;
124 return false;
127 bool ExtensionSpecialStoragePolicy::IsFileHandler(
128 const std::string& extension_id) {
129 base::AutoLock locker(lock_);
130 return file_handler_extensions_.ContainsExtension(extension_id);
133 bool ExtensionSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) {
134 base::AutoLock locker(lock_);
135 return isolated_extensions_.Contains(origin);
138 bool ExtensionSpecialStoragePolicy::NeedsProtection(
139 const extensions::Extension* extension) {
140 return extension->is_hosted_app() && !extension->from_bookmark();
143 const extensions::ExtensionSet*
144 ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin(
145 const GURL& origin) {
146 base::AutoLock locker(lock_);
147 return protected_apps_.ExtensionsContaining(origin);
150 void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
151 const extensions::Extension* extension,
152 content::BrowserContext* browser_context) {
153 DCHECK(extension);
154 if (!(NeedsProtection(extension) ||
155 extension->permissions_data()->HasAPIPermission(
156 APIPermission::kUnlimitedStorage) ||
157 extension->permissions_data()->HasAPIPermission(
158 APIPermission::kFileBrowserHandler) ||
159 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
160 extension->is_app())) {
161 return;
164 int change_flags = 0;
166 base::AutoLock locker(lock_);
167 if (NeedsProtection(extension) && protected_apps_.Add(extension))
168 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
169 // FIXME: Does GrantRightsForExtension imply |extension| is installed?
170 if (extension->is_app())
171 installed_apps_.Add(extension);
173 if (extension->permissions_data()->HasAPIPermission(
174 APIPermission::kUnlimitedStorage) &&
175 unlimited_extensions_.Add(extension)) {
176 if (extension->is_hosted_app())
177 LogHostedAppUnlimitedStorageUsage(extension, browser_context);
179 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
182 if (extension->permissions_data()->HasAPIPermission(
183 APIPermission::kFileBrowserHandler))
184 file_handler_extensions_.Add(extension);
186 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
187 isolated_extensions_.Add(extension);
190 if (change_flags) {
191 NotifyGranted(Extension::GetBaseURLFromExtensionId(extension->id()),
192 change_flags);
196 void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
197 const extensions::Extension* extension) {
198 DCHECK(extension);
199 if (!(NeedsProtection(extension) ||
200 extension->permissions_data()->HasAPIPermission(
201 APIPermission::kUnlimitedStorage) ||
202 extension->permissions_data()->HasAPIPermission(
203 APIPermission::kFileBrowserHandler) ||
204 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
205 extension->is_app())) {
206 return;
208 int change_flags = 0;
210 base::AutoLock locker(lock_);
211 if (NeedsProtection(extension) && protected_apps_.Remove(extension))
212 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
214 if (extension->is_app())
215 installed_apps_.Remove(extension);
217 if (extension->permissions_data()->HasAPIPermission(
218 APIPermission::kUnlimitedStorage) &&
219 unlimited_extensions_.Remove(extension))
220 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
222 if (extension->permissions_data()->HasAPIPermission(
223 APIPermission::kFileBrowserHandler))
224 file_handler_extensions_.Remove(extension);
226 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
227 isolated_extensions_.Remove(extension);
230 if (change_flags) {
231 NotifyRevoked(Extension::GetBaseURLFromExtensionId(extension->id()),
232 change_flags);
236 void ExtensionSpecialStoragePolicy::RevokeRightsForAllExtensions() {
238 base::AutoLock locker(lock_);
239 protected_apps_.Clear();
240 installed_apps_.Clear();
241 unlimited_extensions_.Clear();
242 file_handler_extensions_.Clear();
243 isolated_extensions_.Clear();
246 NotifyCleared();
249 void ExtensionSpecialStoragePolicy::NotifyGranted(
250 const GURL& origin,
251 int change_flags) {
252 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
253 BrowserThread::PostTask(
254 BrowserThread::IO, FROM_HERE,
255 base::Bind(&ExtensionSpecialStoragePolicy::NotifyGranted, this,
256 origin, change_flags));
257 return;
259 SpecialStoragePolicy::NotifyGranted(origin, change_flags);
262 void ExtensionSpecialStoragePolicy::NotifyRevoked(
263 const GURL& origin,
264 int change_flags) {
265 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
266 BrowserThread::PostTask(
267 BrowserThread::IO, FROM_HERE,
268 base::Bind(&ExtensionSpecialStoragePolicy::NotifyRevoked, this,
269 origin, change_flags));
270 return;
272 SpecialStoragePolicy::NotifyRevoked(origin, change_flags);
275 void ExtensionSpecialStoragePolicy::NotifyCleared() {
276 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
277 BrowserThread::PostTask(
278 BrowserThread::IO, FROM_HERE,
279 base::Bind(&ExtensionSpecialStoragePolicy::NotifyCleared, this));
280 return;
282 SpecialStoragePolicy::NotifyCleared();
285 //-----------------------------------------------------------------------------
286 // SpecialCollection helper class
287 //-----------------------------------------------------------------------------
289 ExtensionSpecialStoragePolicy::SpecialCollection::SpecialCollection() {}
291 ExtensionSpecialStoragePolicy::SpecialCollection::~SpecialCollection() {
292 STLDeleteValues(&cached_results_);
295 bool ExtensionSpecialStoragePolicy::SpecialCollection::Contains(
296 const GURL& origin) {
297 return !ExtensionsContaining(origin)->is_empty();
300 const extensions::ExtensionSet*
301 ExtensionSpecialStoragePolicy::SpecialCollection::ExtensionsContaining(
302 const GURL& origin) {
303 CachedResults::const_iterator found = cached_results_.find(origin);
304 if (found != cached_results_.end())
305 return found->second;
307 extensions::ExtensionSet* result = new extensions::ExtensionSet();
308 for (extensions::ExtensionSet::const_iterator iter = extensions_.begin();
309 iter != extensions_.end(); ++iter) {
310 if ((*iter)->OverlapsWithOrigin(origin))
311 result->Insert(*iter);
313 cached_results_[origin] = result;
314 return result;
317 bool ExtensionSpecialStoragePolicy::SpecialCollection::ContainsExtension(
318 const std::string& extension_id) {
319 return extensions_.Contains(extension_id);
322 bool ExtensionSpecialStoragePolicy::SpecialCollection::Add(
323 const extensions::Extension* extension) {
324 ClearCache();
325 return extensions_.Insert(extension);
328 bool ExtensionSpecialStoragePolicy::SpecialCollection::Remove(
329 const extensions::Extension* extension) {
330 ClearCache();
331 return extensions_.Remove(extension->id());
334 void ExtensionSpecialStoragePolicy::SpecialCollection::Clear() {
335 ClearCache();
336 extensions_.Clear();
339 void ExtensionSpecialStoragePolicy::SpecialCollection::ClearCache() {
340 STLDeleteValues(&cached_results_);
341 cached_results_.clear();