Make sure the win_chromium_gn_x64_dbg bot is using symbol_level=1
[chromium-blink-merge.git] / chrome / browser / android / preferences / website_preference_bridge.cc
blob24095c8cd02ec7da4901bbed7bb9c0597c720053
1 // Copyright 2015 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/android/preferences/website_preference_bridge.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_path.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
15 #include "chrome/browser/browsing_data/cookies_tree_model.h"
16 #include "chrome/browser/browsing_data/local_data_container.h"
17 #include "chrome/browser/content_settings/cookie_settings_factory.h"
18 #include "chrome/browser/content_settings/web_site_settings_uma_util.h"
19 #include "chrome/browser/notifications/desktop_notification_profile_util.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "components/content_settings/core/browser/cookie_settings.h"
23 #include "components/content_settings/core/browser/host_content_settings_map.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "jni/WebsitePreferenceBridge_jni.h"
27 #include "storage/browser/quota/quota_client.h"
28 #include "storage/browser/quota/quota_manager.h"
29 #include "url/url_constants.h"
31 using base::android::ConvertJavaStringToUTF8;
32 using base::android::ConvertUTF8ToJavaString;
33 using base::android::JavaRef;
34 using base::android::ScopedJavaGlobalRef;
35 using base::android::ScopedJavaLocalRef;
36 using content::BrowserThread;
38 static Profile* GetActiveUserProfile(bool is_incognito) {
39 Profile* profile = ProfileManager::GetActiveUserProfile();
40 if (is_incognito)
41 profile = profile->GetOffTheRecordProfile();
42 return profile;
45 static HostContentSettingsMap* GetHostContentSettingsMap(bool is_incognito) {
46 return GetActiveUserProfile(is_incognito)->GetHostContentSettingsMap();
49 static void GetOrigins(JNIEnv* env,
50 ContentSettingsType content_type,
51 jobject list,
52 jboolean managedOnly) {
53 ContentSettingsForOneType all_settings;
54 HostContentSettingsMap* content_settings_map =
55 GetHostContentSettingsMap(false);
56 content_settings_map->GetSettingsForOneType(
57 content_type, std::string(), &all_settings);
58 ContentSetting default_content_setting = content_settings_map->
59 GetDefaultContentSetting(content_type, NULL);
60 // Now add all origins that have a non-default setting to the list.
61 for (const auto& settings_it : all_settings) {
62 if (settings_it.setting == default_content_setting)
63 continue;
64 if (managedOnly &&
65 HostContentSettingsMap::GetProviderTypeFromSource(settings_it.source) !=
66 HostContentSettingsMap::ProviderType::POLICY_PROVIDER) {
67 continue;
69 const std::string origin = settings_it.primary_pattern.ToString();
70 const std::string embedder = settings_it.secondary_pattern.ToString();
72 // The string |jorigin| is used to group permissions together in the Site
73 // Settings list. In order to group sites with the same origin, remove any
74 // standard port from the end of the URL if it's present (i.e. remove :443
75 // for HTTPS sites and :80 for HTTP sites).
76 // TODO(sashab,lgarron): Find out which settings are being saved with the
77 // port and omit it if it's the standard port.
78 // TODO(mvanouwerkerk): Remove all this logic and take two passes through
79 // HostContentSettingsMap: once to get all the 'interesting' hosts, and once
80 // (on SingleWebsitePreferences) to find permission patterns which match
81 // each of these hosts.
82 const char* kHttpPortSuffix = ":80";
83 const char* kHttpsPortSuffix = ":443";
84 ScopedJavaLocalRef<jstring> jorigin;
85 if (base::StartsWith(origin, url::kHttpsScheme,
86 base::CompareCase::INSENSITIVE_ASCII) &&
87 base::EndsWith(origin, kHttpsPortSuffix,
88 base::CompareCase::INSENSITIVE_ASCII)) {
89 jorigin = ConvertUTF8ToJavaString(
90 env, origin.substr(0, origin.size() - strlen(kHttpsPortSuffix)));
91 } else if (base::StartsWith(origin, url::kHttpScheme,
92 base::CompareCase::INSENSITIVE_ASCII) &&
93 base::EndsWith(origin, kHttpPortSuffix,
94 base::CompareCase::INSENSITIVE_ASCII)) {
95 jorigin = ConvertUTF8ToJavaString(
96 env, origin.substr(0, origin.size() - strlen(kHttpPortSuffix)));
97 } else {
98 jorigin = ConvertUTF8ToJavaString(env, origin);
101 ScopedJavaLocalRef<jstring> jembedder;
102 if (embedder != origin)
103 jembedder = ConvertUTF8ToJavaString(env, embedder);
104 switch (content_type) {
105 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
106 Java_WebsitePreferenceBridge_insertMicrophoneInfoIntoList(
107 env, list, jorigin.obj(), jembedder.obj());
108 break;
109 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
110 Java_WebsitePreferenceBridge_insertCameraInfoIntoList(
111 env, list, jorigin.obj(), jembedder.obj());
112 break;
113 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
114 Java_WebsitePreferenceBridge_insertGeolocationInfoIntoList(
115 env, list, jorigin.obj(), jembedder.obj());
116 break;
117 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
118 Java_WebsitePreferenceBridge_insertMidiInfoIntoList(
119 env, list, jorigin.obj(), jembedder.obj());
120 break;
121 case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
122 Java_WebsitePreferenceBridge_insertProtectedMediaIdentifierInfoIntoList(
123 env, list, jorigin.obj(), jembedder.obj());
124 break;
125 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
126 Java_WebsitePreferenceBridge_insertPushNotificationIntoList(
127 env, list, jorigin.obj(), jembedder.obj());
128 break;
129 case CONTENT_SETTINGS_TYPE_FULLSCREEN:
130 Java_WebsitePreferenceBridge_insertFullscreenInfoIntoList(
131 env, list, jorigin.obj(), jembedder.obj());
132 break;
133 default:
134 DCHECK(false);
135 break;
140 static jint GetSettingForOrigin(JNIEnv* env,
141 ContentSettingsType content_type,
142 jstring origin,
143 jstring embedder,
144 jboolean is_incognito) {
145 GURL url(ConvertJavaStringToUTF8(env, origin));
146 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
147 ContentSetting setting =
148 GetHostContentSettingsMap(is_incognito)
149 ->GetContentSetting(url, embedder_url, content_type, std::string());
150 return setting;
153 static void SetSettingForOrigin(JNIEnv* env,
154 ContentSettingsType content_type,
155 jstring origin,
156 ContentSettingsPattern secondary_pattern,
157 jint value,
158 jboolean is_incognito) {
159 GURL url(ConvertJavaStringToUTF8(env, origin));
160 ContentSetting setting = CONTENT_SETTING_DEFAULT;
161 switch (value) {
162 case -1: break;
163 case 0: setting = CONTENT_SETTING_DEFAULT; break;
164 case 1: setting = CONTENT_SETTING_ALLOW; break;
165 case 2: setting = CONTENT_SETTING_BLOCK; break;
166 default:
167 // Note: CONTENT_SETTINGS_ASK is not and should not be supported.
168 NOTREACHED();
170 GetHostContentSettingsMap(is_incognito)
171 ->SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(url),
172 secondary_pattern, content_type, std::string(),
173 setting);
174 WebSiteSettingsUmaUtil::LogPermissionChange(content_type, setting);
177 static void GetFullscreenOrigins(JNIEnv* env,
178 jclass clazz,
179 jobject list,
180 jboolean managedOnly) {
181 GetOrigins(env, CONTENT_SETTINGS_TYPE_FULLSCREEN, list, managedOnly);
184 static jint GetFullscreenSettingForOrigin(JNIEnv* env,
185 jclass clazz,
186 jstring origin,
187 jstring embedder,
188 jboolean is_incognito) {
189 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_FULLSCREEN, origin,
190 embedder, is_incognito);
193 static void SetFullscreenSettingForOrigin(JNIEnv* env,
194 jclass clazz,
195 jstring origin,
196 jstring embedder,
197 jint value,
198 jboolean is_incognito) {
199 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
200 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_FULLSCREEN, origin,
201 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
202 value, is_incognito);
205 static void GetGeolocationOrigins(JNIEnv* env,
206 jclass clazz,
207 jobject list,
208 jboolean managedOnly) {
209 GetOrigins(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, list, managedOnly);
212 static jint GetGeolocationSettingForOrigin(JNIEnv* env,
213 jclass clazz,
214 jstring origin,
215 jstring embedder,
216 jboolean is_incognito) {
217 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, origin,
218 embedder, is_incognito);
221 static void SetGeolocationSettingForOrigin(JNIEnv* env,
222 jclass clazz,
223 jstring origin,
224 jstring embedder,
225 jint value,
226 jboolean is_incognito) {
227 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
228 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, origin,
229 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
230 value, is_incognito);
233 static void GetMidiOrigins(JNIEnv* env, jclass clazz, jobject list) {
234 GetOrigins(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, list, false);
237 static jint GetMidiSettingForOrigin(JNIEnv* env,
238 jclass clazz,
239 jstring origin,
240 jstring embedder,
241 jboolean is_incognito) {
242 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, origin,
243 embedder, is_incognito);
246 static void SetMidiSettingForOrigin(JNIEnv* env,
247 jclass clazz,
248 jstring origin,
249 jstring embedder,
250 jint value,
251 jboolean is_incognito) {
252 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
253 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, origin,
254 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
255 value, is_incognito);
258 static void GetProtectedMediaIdentifierOrigins(JNIEnv* env, jclass clazz,
259 jobject list) {
260 GetOrigins(env, CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, list,
261 false);
264 static jint GetProtectedMediaIdentifierSettingForOrigin(JNIEnv* env,
265 jclass clazz,
266 jstring origin,
267 jstring embedder,
268 jboolean is_incognito) {
269 return GetSettingForOrigin(env,
270 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
271 origin, embedder, is_incognito);
274 static void SetProtectedMediaIdentifierSettingForOrigin(JNIEnv* env,
275 jclass clazz,
276 jstring origin,
277 jstring embedder,
278 jint value,
279 jboolean is_incognito) {
280 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
281 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
282 origin,
283 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
284 value, is_incognito);
287 static void GetPushNotificationOrigins(JNIEnv* env,
288 jclass clazz,
289 jobject list) {
290 GetOrigins(env, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, list, false);
293 static jint GetPushNotificationSettingForOrigin(JNIEnv* env,
294 jclass clazz,
295 jstring origin,
296 jstring embedder,
297 jboolean is_incognito) {
298 return DesktopNotificationProfileUtil::GetContentSetting(
299 GetActiveUserProfile(is_incognito),
300 GURL(ConvertJavaStringToUTF8(env, origin)));
303 static void SetPushNotificationSettingForOrigin(JNIEnv* env,
304 jclass clazz,
305 jstring origin,
306 jstring embedder,
307 jint value,
308 jboolean is_incognito) {
309 // TODO(peter): Web Notification permission behaves differently from all other
310 // permission types. See https://crbug.com/416894.
311 Profile* profile = GetActiveUserProfile(is_incognito);
312 GURL url = GURL(ConvertJavaStringToUTF8(env, origin));
313 ContentSetting setting = CONTENT_SETTING_DEFAULT;
314 switch (value) {
315 case -1:
316 DesktopNotificationProfileUtil::ClearSetting(
317 profile, ContentSettingsPattern::FromURLNoWildcard(url));
318 break;
319 case 1:
320 DesktopNotificationProfileUtil::GrantPermission(profile, url);
321 setting = CONTENT_SETTING_ALLOW;
322 break;
323 case 2:
324 DesktopNotificationProfileUtil::DenyPermission(profile, url);
325 setting = CONTENT_SETTING_BLOCK;
326 break;
327 default:
328 NOTREACHED();
330 WebSiteSettingsUmaUtil::LogPermissionChange(
331 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
334 static void GetCameraOrigins(JNIEnv* env,
335 jclass clazz,
336 jobject list,
337 jboolean managedOnly) {
338 GetOrigins(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, list, managedOnly);
341 static void GetMicrophoneOrigins(JNIEnv* env,
342 jclass clazz,
343 jobject list,
344 jboolean managedOnly) {
345 GetOrigins(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, list, managedOnly);
348 static jint GetMicrophoneSettingForOrigin(JNIEnv* env,
349 jclass clazz,
350 jstring origin,
351 jstring embedder,
352 jboolean is_incognito) {
353 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, origin,
354 embedder, is_incognito);
357 static jint GetCameraSettingForOrigin(JNIEnv* env,
358 jclass clazz,
359 jstring origin,
360 jstring embedder,
361 jboolean is_incognito) {
362 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
363 origin, embedder, is_incognito);
366 static void SetMicrophoneSettingForOrigin(JNIEnv* env,
367 jclass clazz,
368 jstring origin,
369 jstring embedder,
370 jint value,
371 jboolean is_incognito) {
372 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, origin,
373 ContentSettingsPattern::Wildcard(), value, is_incognito);
376 static void SetCameraSettingForOrigin(JNIEnv* env,
377 jclass clazz,
378 jstring origin,
379 jstring embedder,
380 jint value,
381 jboolean is_incognito) {
382 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, origin,
383 ContentSettingsPattern::Wildcard(), value, is_incognito);
386 static scoped_refptr<content_settings::CookieSettings> GetCookieSettings() {
387 // A single cookie setting applies to both incognito and non-incognito.
388 Profile* profile = ProfileManager::GetActiveUserProfile();
389 return CookieSettingsFactory::GetForProfile(profile);
392 static void GetCookieOrigins(JNIEnv* env,
393 jclass clazz,
394 jobject list,
395 jboolean managedOnly) {
396 ContentSettingsForOneType all_settings;
397 GetCookieSettings()->GetCookieSettings(&all_settings);
398 const ContentSetting default_setting =
399 GetCookieSettings()->GetDefaultCookieSetting(nullptr);
400 for (const auto& settings_it : all_settings) {
401 if (settings_it.setting == default_setting)
402 continue;
403 if (managedOnly &&
404 HostContentSettingsMap::GetProviderTypeFromSource(settings_it.source) !=
405 HostContentSettingsMap::ProviderType::POLICY_PROVIDER) {
406 continue;
408 const std::string& origin = settings_it.primary_pattern.ToString();
409 const std::string& embedder = settings_it.secondary_pattern.ToString();
410 ScopedJavaLocalRef<jstring> jorigin = ConvertUTF8ToJavaString(env, origin);
411 ScopedJavaLocalRef<jstring> jembedder;
412 if (embedder != origin)
413 jembedder = ConvertUTF8ToJavaString(env, embedder);
414 Java_WebsitePreferenceBridge_insertCookieInfoIntoList(env, list,
415 jorigin.obj(), jembedder.obj());
419 static jint GetCookieSettingForOrigin(JNIEnv* env,
420 jclass clazz,
421 jstring origin,
422 jstring embedder,
423 jboolean is_incognito) {
424 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_COOKIES, origin,
425 embedder, false);
428 static void SetCookieSettingForOrigin(JNIEnv* env,
429 jclass clazz,
430 jstring origin,
431 jstring embedder,
432 jint value,
433 jboolean is_incognito) {
434 GURL url(ConvertJavaStringToUTF8(env, origin));
435 ContentSettingsPattern primary_pattern(
436 ContentSettingsPattern::FromURLNoWildcard(url));
437 ContentSettingsPattern secondary_pattern(ContentSettingsPattern::Wildcard());
438 ContentSetting setting = CONTENT_SETTING_DEFAULT;
439 if (value == -1) {
440 GetCookieSettings()->ResetCookieSetting(primary_pattern, secondary_pattern);
441 } else {
442 setting = value ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
443 GetCookieSettings()->SetCookieSetting(primary_pattern, secondary_pattern,
444 setting);
446 WebSiteSettingsUmaUtil::LogPermissionChange(
447 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
450 static jboolean IsContentSettingsPatternValid(JNIEnv* env, jclass clazz,
451 jstring pattern) {
452 return ContentSettingsPattern::FromString(
453 ConvertJavaStringToUTF8(env, pattern)).IsValid();
456 static jboolean UrlMatchesContentSettingsPattern(JNIEnv* env,
457 jclass clazz,
458 jstring jurl,
459 jstring jpattern) {
460 ContentSettingsPattern pattern = ContentSettingsPattern::FromString(
461 ConvertJavaStringToUTF8(env, jpattern));
462 return pattern.Matches(GURL(ConvertJavaStringToUTF8(env, jurl)));
465 namespace {
467 class SiteDataDeleteHelper :
468 public base::RefCountedThreadSafe<SiteDataDeleteHelper>,
469 public CookiesTreeModel::Observer {
470 public:
471 SiteDataDeleteHelper(Profile* profile, const GURL& domain)
472 : profile_(profile), domain_(domain), ending_batch_processing_(false) {
475 void Run() {
476 AddRef(); // Balanced in TreeModelEndBatch.
478 content::StoragePartition* storage_partition =
479 content::BrowserContext::GetDefaultStoragePartition(profile_);
480 content::IndexedDBContext* indexed_db_context =
481 storage_partition->GetIndexedDBContext();
482 content::ServiceWorkerContext* service_worker_context =
483 storage_partition->GetServiceWorkerContext();
484 content::CacheStorageContext* cache_storage_context =
485 storage_partition->GetCacheStorageContext();
486 storage::FileSystemContext* file_system_context =
487 storage_partition->GetFileSystemContext();
488 LocalDataContainer* container = new LocalDataContainer(
489 new BrowsingDataCookieHelper(profile_->GetRequestContext()),
490 new BrowsingDataDatabaseHelper(profile_),
491 new BrowsingDataLocalStorageHelper(profile_),
492 NULL,
493 new BrowsingDataAppCacheHelper(profile_),
494 new BrowsingDataIndexedDBHelper(indexed_db_context),
495 BrowsingDataFileSystemHelper::Create(file_system_context),
496 BrowsingDataQuotaHelper::Create(profile_),
497 BrowsingDataChannelIDHelper::Create(profile_->GetRequestContext()),
498 new BrowsingDataServiceWorkerHelper(service_worker_context),
499 new BrowsingDataCacheStorageHelper(cache_storage_context),
500 NULL);
502 cookies_tree_model_.reset(new CookiesTreeModel(
503 container, profile_->GetExtensionSpecialStoragePolicy(), false));
504 cookies_tree_model_->AddCookiesTreeObserver(this);
507 // TreeModelObserver:
508 void TreeNodesAdded(ui::TreeModel* model,
509 ui::TreeModelNode* parent,
510 int start,
511 int count) override {}
512 void TreeNodesRemoved(ui::TreeModel* model,
513 ui::TreeModelNode* parent,
514 int start,
515 int count) override {}
517 // CookiesTreeModel::Observer:
518 void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) override {
521 void TreeModelBeginBatch(CookiesTreeModel* model) override {
522 DCHECK(!ending_batch_processing_); // Extra batch-start sent.
525 void TreeModelEndBatch(CookiesTreeModel* model) override {
526 DCHECK(!ending_batch_processing_); // Already in end-stage.
527 ending_batch_processing_ = true;
529 RecursivelyFindSiteAndDelete(cookies_tree_model_->GetRoot());
531 // This will result in this class getting deleted.
532 Release();
535 void RecursivelyFindSiteAndDelete(CookieTreeNode* node) {
536 CookieTreeNode::DetailedInfo info = node->GetDetailedInfo();
537 for (int i = node->child_count(); i > 0; --i)
538 RecursivelyFindSiteAndDelete(node->GetChild(i - 1));
540 if (info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE &&
541 info.cookie &&
542 domain_.DomainIs(info.cookie->Domain().c_str()))
543 cookies_tree_model_->DeleteCookieNode(node);
546 private:
547 friend class base::RefCountedThreadSafe<SiteDataDeleteHelper>;
549 ~SiteDataDeleteHelper() override {}
551 Profile* profile_;
553 // The domain we want to delete data for.
554 GURL domain_;
556 // Keeps track of when we're ready to close batch processing.
557 bool ending_batch_processing_;
559 scoped_ptr<CookiesTreeModel> cookies_tree_model_;
561 DISALLOW_COPY_AND_ASSIGN(SiteDataDeleteHelper);
564 class StorageInfoFetcher :
565 public base::RefCountedThreadSafe<StorageInfoFetcher> {
566 public:
567 StorageInfoFetcher(storage::QuotaManager* quota_manager,
568 const JavaRef<jobject>& java_callback)
569 : env_(base::android::AttachCurrentThread()),
570 quota_manager_(quota_manager),
571 java_callback_(java_callback) {
574 void Run() {
575 // QuotaManager must be called on IO thread, but java_callback must then be
576 // called back on UI thread.
577 BrowserThread::PostTask(
578 BrowserThread::IO, FROM_HERE,
579 base::Bind(&StorageInfoFetcher::GetUsageInfo, this));
582 protected:
583 virtual ~StorageInfoFetcher() {}
585 private:
586 friend class base::RefCountedThreadSafe<StorageInfoFetcher>;
588 void GetUsageInfo() {
589 // We will have no explicit owner as soon as we leave this method.
590 AddRef();
591 quota_manager_->GetUsageInfo(
592 base::Bind(&StorageInfoFetcher::OnGetUsageInfo, this));
595 void OnGetUsageInfo(const storage::UsageInfoEntries& entries) {
596 entries_.insert(entries_.begin(), entries.begin(), entries.end());
597 BrowserThread::PostTask(
598 BrowserThread::UI, FROM_HERE,
599 base::Bind(&StorageInfoFetcher::InvokeCallback, this));
600 Release();
603 void InvokeCallback() {
604 ScopedJavaLocalRef<jobject> list =
605 Java_WebsitePreferenceBridge_createStorageInfoList(env_);
607 storage::UsageInfoEntries::const_iterator i;
608 for (i = entries_.begin(); i != entries_.end(); ++i) {
609 if (i->usage <= 0) continue;
610 ScopedJavaLocalRef<jstring> host =
611 ConvertUTF8ToJavaString(env_, i->host);
613 Java_WebsitePreferenceBridge_insertStorageInfoIntoList(
614 env_, list.obj(), host.obj(), i->type, i->usage);
616 Java_StorageInfoReadyCallback_onStorageInfoReady(
617 env_, java_callback_.obj(), list.obj());
620 JNIEnv* env_;
621 storage::QuotaManager* quota_manager_;
622 ScopedJavaGlobalRef<jobject> java_callback_;
623 storage::UsageInfoEntries entries_;
625 DISALLOW_COPY_AND_ASSIGN(StorageInfoFetcher);
628 class StorageDataDeleter :
629 public base::RefCountedThreadSafe<StorageDataDeleter> {
630 public:
631 StorageDataDeleter(storage::QuotaManager* quota_manager,
632 const std::string& host,
633 storage::StorageType type,
634 const JavaRef<jobject>& java_callback)
635 : env_(base::android::AttachCurrentThread()),
636 quota_manager_(quota_manager),
637 host_(host),
638 type_(type),
639 java_callback_(java_callback) {
642 void Run() {
643 // QuotaManager must be called on IO thread, but java_callback must then be
644 // called back on UI thread. Grant ourself an extra reference to avoid
645 // being deleted after DeleteHostData will return.
646 AddRef();
647 BrowserThread::PostTask(
648 BrowserThread::IO, FROM_HERE,
649 base::Bind(&storage::QuotaManager::DeleteHostData,
650 quota_manager_,
651 host_,
652 type_,
653 storage::QuotaClient::kAllClientsMask,
654 base::Bind(&StorageDataDeleter::OnHostDataDeleted,
655 this)));
658 protected:
659 virtual ~StorageDataDeleter() {}
661 private:
662 friend class base::RefCountedThreadSafe<StorageDataDeleter>;
664 void OnHostDataDeleted(storage::QuotaStatusCode) {
665 DCHECK_CURRENTLY_ON(BrowserThread::IO);
666 quota_manager_->ResetUsageTracker(type_);
667 BrowserThread::PostTask(
668 BrowserThread::UI, FROM_HERE,
669 base::Bind(&StorageDataDeleter::InvokeCallback, this));
670 Release();
673 void InvokeCallback() {
674 Java_StorageInfoClearedCallback_onStorageInfoCleared(
675 env_, java_callback_.obj());
678 JNIEnv* env_;
679 storage::QuotaManager* quota_manager_;
680 std::string host_;
681 storage::StorageType type_;
682 ScopedJavaGlobalRef<jobject> java_callback_;
685 class LocalStorageInfoReadyCallback {
686 public:
687 LocalStorageInfoReadyCallback(
688 const ScopedJavaLocalRef<jobject>& java_callback)
689 : env_(base::android::AttachCurrentThread()),
690 java_callback_(java_callback) {
693 void OnLocalStorageModelInfoLoaded(
694 const std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>&
695 local_storage_info) {
696 ScopedJavaLocalRef<jobject> map =
697 Java_WebsitePreferenceBridge_createLocalStorageInfoMap(env_);
699 std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>::const_iterator
701 for (i = local_storage_info.begin(); i != local_storage_info.end(); ++i) {
702 ScopedJavaLocalRef<jstring> full_origin =
703 ConvertUTF8ToJavaString(env_, i->origin_url.spec());
704 // Remove the trailing backslash so the origin is matched correctly in
705 // SingleWebsitePreferences.mergePermissionInfoForTopLevelOrigin.
706 std::string origin_str = i->origin_url.GetOrigin().spec();
707 DCHECK(origin_str[origin_str.size() - 1] == '/');
708 origin_str = origin_str.substr(0, origin_str.size() - 1);
709 ScopedJavaLocalRef<jstring> origin =
710 ConvertUTF8ToJavaString(env_, origin_str);
711 Java_WebsitePreferenceBridge_insertLocalStorageInfoIntoMap(
712 env_, map.obj(), origin.obj(), full_origin.obj(), i->size);
715 Java_LocalStorageInfoReadyCallback_onLocalStorageInfoReady(
716 env_, java_callback_.obj(), map.obj());
717 delete this;
720 private:
721 JNIEnv* env_;
722 ScopedJavaGlobalRef<jobject> java_callback_;
725 } // anonymous namespace
727 // TODO(jknotten): These methods should not be static. Instead we should
728 // expose a class to Java so that the fetch requests can be cancelled,
729 // and manage the lifetimes of the callback (and indirectly the helper
730 // by having a reference to it).
732 // The helper methods (StartFetching, DeleteLocalStorageFile, DeleteDatabase)
733 // are asynchronous. A "use after free" error is not possible because the
734 // helpers keep a reference to themselves for the duration of their tasks,
735 // which includes callback invocation.
737 static void FetchLocalStorageInfo(JNIEnv* env, jclass clazz,
738 jobject java_callback) {
739 Profile* profile = ProfileManager::GetActiveUserProfile();
740 scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper(
741 new BrowsingDataLocalStorageHelper(profile));
742 // local_storage_callback will delete itself when it is run.
743 LocalStorageInfoReadyCallback* local_storage_callback =
744 new LocalStorageInfoReadyCallback(
745 ScopedJavaLocalRef<jobject>(env, java_callback));
746 local_storage_helper->StartFetching(
747 base::Bind(&LocalStorageInfoReadyCallback::OnLocalStorageModelInfoLoaded,
748 base::Unretained(local_storage_callback)));
751 static void FetchStorageInfo(JNIEnv* env, jclass clazz, jobject java_callback) {
752 Profile* profile = ProfileManager::GetActiveUserProfile();
753 scoped_refptr<StorageInfoFetcher> storage_info_fetcher(new StorageInfoFetcher(
754 content::BrowserContext::GetDefaultStoragePartition(
755 profile)->GetQuotaManager(),
756 ScopedJavaLocalRef<jobject>(env, java_callback)));
757 storage_info_fetcher->Run();
760 static void ClearLocalStorageData(JNIEnv* env, jclass clazz, jstring jorigin) {
761 Profile* profile = ProfileManager::GetActiveUserProfile();
762 scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper =
763 new BrowsingDataLocalStorageHelper(profile);
764 GURL origin_url = GURL(ConvertJavaStringToUTF8(env, jorigin));
765 local_storage_helper->DeleteOrigin(origin_url);
768 static void ClearStorageData(JNIEnv* env,
769 jclass clazz,
770 jstring jhost,
771 jint type,
772 jobject java_callback) {
773 Profile* profile = ProfileManager::GetActiveUserProfile();
774 std::string host = ConvertJavaStringToUTF8(env, jhost);
775 scoped_refptr<StorageDataDeleter> storage_data_deleter(new StorageDataDeleter(
776 content::BrowserContext::GetDefaultStoragePartition(
777 profile)->GetQuotaManager(),
778 host,
779 static_cast<storage::StorageType>(type),
780 ScopedJavaLocalRef<jobject>(env, java_callback)));
781 storage_data_deleter->Run();
784 static void ClearCookieData(JNIEnv* env, jclass clazz, jstring jorigin) {
785 Profile* profile = ProfileManager::GetActiveUserProfile();
786 GURL url(ConvertJavaStringToUTF8(env, jorigin));
787 scoped_refptr<SiteDataDeleteHelper> site_data_deleter(
788 new SiteDataDeleteHelper(profile, url));
789 site_data_deleter->Run();
792 // Register native methods
793 bool RegisterWebsitePreferenceBridge(JNIEnv* env) {
794 return RegisterNativesImpl(env);