Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / android / preferences / website_preference_bridge.cc
blob9d1f8e9ab2d59ca024fefd4713a45037f9f7f096
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 const JavaParamRef<jclass>& clazz,
179 const JavaParamRef<jobject>& list,
180 jboolean managedOnly) {
181 GetOrigins(env, CONTENT_SETTINGS_TYPE_FULLSCREEN, list, managedOnly);
184 static jint GetFullscreenSettingForOrigin(JNIEnv* env,
185 const JavaParamRef<jclass>& clazz,
186 const JavaParamRef<jstring>& origin,
187 const JavaParamRef<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 const JavaParamRef<jclass>& clazz,
195 const JavaParamRef<jstring>& origin,
196 const JavaParamRef<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 const JavaParamRef<jclass>& clazz,
207 const JavaParamRef<jobject>& list,
208 jboolean managedOnly) {
209 GetOrigins(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, list, managedOnly);
212 static jint GetGeolocationSettingForOrigin(
213 JNIEnv* env,
214 const JavaParamRef<jclass>& clazz,
215 const JavaParamRef<jstring>& origin,
216 const JavaParamRef<jstring>& embedder,
217 jboolean is_incognito) {
218 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, origin,
219 embedder, is_incognito);
222 static void SetGeolocationSettingForOrigin(
223 JNIEnv* env,
224 const JavaParamRef<jclass>& clazz,
225 const JavaParamRef<jstring>& origin,
226 const JavaParamRef<jstring>& embedder,
227 jint value,
228 jboolean is_incognito) {
229 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
230 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, origin,
231 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
232 value, is_incognito);
235 static void GetMidiOrigins(JNIEnv* env,
236 const JavaParamRef<jclass>& clazz,
237 const JavaParamRef<jobject>& list) {
238 GetOrigins(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, list, false);
241 static jint GetMidiSettingForOrigin(JNIEnv* env,
242 const JavaParamRef<jclass>& clazz,
243 const JavaParamRef<jstring>& origin,
244 const JavaParamRef<jstring>& embedder,
245 jboolean is_incognito) {
246 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, origin,
247 embedder, is_incognito);
250 static void SetMidiSettingForOrigin(JNIEnv* env,
251 const JavaParamRef<jclass>& clazz,
252 const JavaParamRef<jstring>& origin,
253 const JavaParamRef<jstring>& embedder,
254 jint value,
255 jboolean is_incognito) {
256 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
257 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, origin,
258 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
259 value, is_incognito);
262 static void GetProtectedMediaIdentifierOrigins(
263 JNIEnv* env,
264 const JavaParamRef<jclass>& clazz,
265 const JavaParamRef<jobject>& list) {
266 GetOrigins(env, CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, list,
267 false);
270 static jint GetProtectedMediaIdentifierSettingForOrigin(
271 JNIEnv* env,
272 const JavaParamRef<jclass>& clazz,
273 const JavaParamRef<jstring>& origin,
274 const JavaParamRef<jstring>& embedder,
275 jboolean is_incognito) {
276 return GetSettingForOrigin(env,
277 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
278 origin, embedder, is_incognito);
281 static void SetProtectedMediaIdentifierSettingForOrigin(
282 JNIEnv* env,
283 const JavaParamRef<jclass>& clazz,
284 const JavaParamRef<jstring>& origin,
285 const JavaParamRef<jstring>& embedder,
286 jint value,
287 jboolean is_incognito) {
288 GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
289 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
290 origin,
291 ContentSettingsPattern::FromURLNoWildcard(embedder_url),
292 value, is_incognito);
295 static void GetPushNotificationOrigins(JNIEnv* env,
296 const JavaParamRef<jclass>& clazz,
297 const JavaParamRef<jobject>& list) {
298 GetOrigins(env, CONTENT_SETTINGS_TYPE_NOTIFICATIONS, list, false);
301 static jint GetPushNotificationSettingForOrigin(
302 JNIEnv* env,
303 const JavaParamRef<jclass>& clazz,
304 const JavaParamRef<jstring>& origin,
305 const JavaParamRef<jstring>& embedder,
306 jboolean is_incognito) {
307 return DesktopNotificationProfileUtil::GetContentSetting(
308 GetActiveUserProfile(is_incognito),
309 GURL(ConvertJavaStringToUTF8(env, origin)));
312 static void SetPushNotificationSettingForOrigin(
313 JNIEnv* env,
314 const JavaParamRef<jclass>& clazz,
315 const JavaParamRef<jstring>& origin,
316 const JavaParamRef<jstring>& embedder,
317 jint value,
318 jboolean is_incognito) {
319 // TODO(peter): Web Notification permission behaves differently from all other
320 // permission types. See https://crbug.com/416894.
321 Profile* profile = GetActiveUserProfile(is_incognito);
322 GURL url = GURL(ConvertJavaStringToUTF8(env, origin));
323 ContentSetting setting = CONTENT_SETTING_DEFAULT;
324 switch (value) {
325 case -1:
326 DesktopNotificationProfileUtil::ClearSetting(
327 profile, ContentSettingsPattern::FromURLNoWildcard(url));
328 break;
329 case 1:
330 DesktopNotificationProfileUtil::GrantPermission(profile, url);
331 setting = CONTENT_SETTING_ALLOW;
332 break;
333 case 2:
334 DesktopNotificationProfileUtil::DenyPermission(profile, url);
335 setting = CONTENT_SETTING_BLOCK;
336 break;
337 default:
338 NOTREACHED();
340 WebSiteSettingsUmaUtil::LogPermissionChange(
341 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
344 static void GetCameraOrigins(JNIEnv* env,
345 const JavaParamRef<jclass>& clazz,
346 const JavaParamRef<jobject>& list,
347 jboolean managedOnly) {
348 GetOrigins(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, list, managedOnly);
351 static void GetMicrophoneOrigins(JNIEnv* env,
352 const JavaParamRef<jclass>& clazz,
353 const JavaParamRef<jobject>& list,
354 jboolean managedOnly) {
355 GetOrigins(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, list, managedOnly);
358 static jint GetMicrophoneSettingForOrigin(JNIEnv* env,
359 const JavaParamRef<jclass>& clazz,
360 const JavaParamRef<jstring>& origin,
361 const JavaParamRef<jstring>& embedder,
362 jboolean is_incognito) {
363 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, origin,
364 embedder, is_incognito);
367 static jint GetCameraSettingForOrigin(JNIEnv* env,
368 const JavaParamRef<jclass>& clazz,
369 const JavaParamRef<jstring>& origin,
370 const JavaParamRef<jstring>& embedder,
371 jboolean is_incognito) {
372 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
373 origin, embedder, is_incognito);
376 static void SetMicrophoneSettingForOrigin(JNIEnv* env,
377 const JavaParamRef<jclass>& clazz,
378 const JavaParamRef<jstring>& origin,
379 const JavaParamRef<jstring>& embedder,
380 jint value,
381 jboolean is_incognito) {
382 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, origin,
383 ContentSettingsPattern::Wildcard(), value, is_incognito);
386 static void SetCameraSettingForOrigin(JNIEnv* env,
387 const JavaParamRef<jclass>& clazz,
388 const JavaParamRef<jstring>& origin,
389 const JavaParamRef<jstring>& embedder,
390 jint value,
391 jboolean is_incognito) {
392 SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, origin,
393 ContentSettingsPattern::Wildcard(), value, is_incognito);
396 static scoped_refptr<content_settings::CookieSettings> GetCookieSettings() {
397 // A single cookie setting applies to both incognito and non-incognito.
398 Profile* profile = ProfileManager::GetActiveUserProfile();
399 return CookieSettingsFactory::GetForProfile(profile);
402 static void GetCookieOrigins(JNIEnv* env,
403 const JavaParamRef<jclass>& clazz,
404 const JavaParamRef<jobject>& list,
405 jboolean managedOnly) {
406 ContentSettingsForOneType all_settings;
407 GetCookieSettings()->GetCookieSettings(&all_settings);
408 const ContentSetting default_setting =
409 GetCookieSettings()->GetDefaultCookieSetting(nullptr);
410 for (const auto& settings_it : all_settings) {
411 if (settings_it.setting == default_setting)
412 continue;
413 if (managedOnly &&
414 HostContentSettingsMap::GetProviderTypeFromSource(settings_it.source) !=
415 HostContentSettingsMap::ProviderType::POLICY_PROVIDER) {
416 continue;
418 const std::string& origin = settings_it.primary_pattern.ToString();
419 const std::string& embedder = settings_it.secondary_pattern.ToString();
420 ScopedJavaLocalRef<jstring> jorigin = ConvertUTF8ToJavaString(env, origin);
421 ScopedJavaLocalRef<jstring> jembedder;
422 if (embedder != origin)
423 jembedder = ConvertUTF8ToJavaString(env, embedder);
424 Java_WebsitePreferenceBridge_insertCookieInfoIntoList(env, list,
425 jorigin.obj(), jembedder.obj());
429 static jint GetCookieSettingForOrigin(JNIEnv* env,
430 const JavaParamRef<jclass>& clazz,
431 const JavaParamRef<jstring>& origin,
432 const JavaParamRef<jstring>& embedder,
433 jboolean is_incognito) {
434 return GetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_COOKIES, origin,
435 embedder, false);
438 static void SetCookieSettingForOrigin(JNIEnv* env,
439 const JavaParamRef<jclass>& clazz,
440 const JavaParamRef<jstring>& origin,
441 const JavaParamRef<jstring>& embedder,
442 jint value,
443 jboolean is_incognito) {
444 GURL url(ConvertJavaStringToUTF8(env, origin));
445 ContentSettingsPattern primary_pattern(
446 ContentSettingsPattern::FromURLNoWildcard(url));
447 ContentSettingsPattern secondary_pattern(ContentSettingsPattern::Wildcard());
448 ContentSetting setting = CONTENT_SETTING_DEFAULT;
449 if (value == -1) {
450 GetCookieSettings()->ResetCookieSetting(primary_pattern, secondary_pattern);
451 } else {
452 setting = value ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
453 GetCookieSettings()->SetCookieSetting(primary_pattern, secondary_pattern,
454 setting);
456 WebSiteSettingsUmaUtil::LogPermissionChange(
457 CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
460 static jboolean IsContentSettingsPatternValid(
461 JNIEnv* env,
462 const JavaParamRef<jclass>& clazz,
463 const JavaParamRef<jstring>& pattern) {
464 return ContentSettingsPattern::FromString(
465 ConvertJavaStringToUTF8(env, pattern)).IsValid();
468 static jboolean UrlMatchesContentSettingsPattern(
469 JNIEnv* env,
470 const JavaParamRef<jclass>& clazz,
471 const JavaParamRef<jstring>& jurl,
472 const JavaParamRef<jstring>& jpattern) {
473 ContentSettingsPattern pattern = ContentSettingsPattern::FromString(
474 ConvertJavaStringToUTF8(env, jpattern));
475 return pattern.Matches(GURL(ConvertJavaStringToUTF8(env, jurl)));
478 namespace {
480 class SiteDataDeleteHelper :
481 public base::RefCountedThreadSafe<SiteDataDeleteHelper>,
482 public CookiesTreeModel::Observer {
483 public:
484 SiteDataDeleteHelper(Profile* profile, const GURL& domain)
485 : profile_(profile), domain_(domain), ending_batch_processing_(false) {
488 void Run() {
489 AddRef(); // Balanced in TreeModelEndBatch.
491 content::StoragePartition* storage_partition =
492 content::BrowserContext::GetDefaultStoragePartition(profile_);
493 content::IndexedDBContext* indexed_db_context =
494 storage_partition->GetIndexedDBContext();
495 content::ServiceWorkerContext* service_worker_context =
496 storage_partition->GetServiceWorkerContext();
497 content::CacheStorageContext* cache_storage_context =
498 storage_partition->GetCacheStorageContext();
499 storage::FileSystemContext* file_system_context =
500 storage_partition->GetFileSystemContext();
501 LocalDataContainer* container = new LocalDataContainer(
502 new BrowsingDataCookieHelper(profile_->GetRequestContext()),
503 new BrowsingDataDatabaseHelper(profile_),
504 new BrowsingDataLocalStorageHelper(profile_),
505 NULL,
506 new BrowsingDataAppCacheHelper(profile_),
507 new BrowsingDataIndexedDBHelper(indexed_db_context),
508 BrowsingDataFileSystemHelper::Create(file_system_context),
509 BrowsingDataQuotaHelper::Create(profile_),
510 BrowsingDataChannelIDHelper::Create(profile_->GetRequestContext()),
511 new BrowsingDataServiceWorkerHelper(service_worker_context),
512 new BrowsingDataCacheStorageHelper(cache_storage_context),
513 NULL);
515 cookies_tree_model_.reset(new CookiesTreeModel(
516 container, profile_->GetExtensionSpecialStoragePolicy(), false));
517 cookies_tree_model_->AddCookiesTreeObserver(this);
520 // TreeModelObserver:
521 void TreeNodesAdded(ui::TreeModel* model,
522 ui::TreeModelNode* parent,
523 int start,
524 int count) override {}
525 void TreeNodesRemoved(ui::TreeModel* model,
526 ui::TreeModelNode* parent,
527 int start,
528 int count) override {}
530 // CookiesTreeModel::Observer:
531 void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) override {
534 void TreeModelBeginBatch(CookiesTreeModel* model) override {
535 DCHECK(!ending_batch_processing_); // Extra batch-start sent.
538 void TreeModelEndBatch(CookiesTreeModel* model) override {
539 DCHECK(!ending_batch_processing_); // Already in end-stage.
540 ending_batch_processing_ = true;
542 RecursivelyFindSiteAndDelete(cookies_tree_model_->GetRoot());
544 // This will result in this class getting deleted.
545 Release();
548 void RecursivelyFindSiteAndDelete(CookieTreeNode* node) {
549 CookieTreeNode::DetailedInfo info = node->GetDetailedInfo();
550 for (int i = node->child_count(); i > 0; --i)
551 RecursivelyFindSiteAndDelete(node->GetChild(i - 1));
553 if (info.node_type == CookieTreeNode::DetailedInfo::TYPE_COOKIE &&
554 info.cookie &&
555 domain_.DomainIs(info.cookie->Domain().c_str()))
556 cookies_tree_model_->DeleteCookieNode(node);
559 private:
560 friend class base::RefCountedThreadSafe<SiteDataDeleteHelper>;
562 ~SiteDataDeleteHelper() override {}
564 Profile* profile_;
566 // The domain we want to delete data for.
567 GURL domain_;
569 // Keeps track of when we're ready to close batch processing.
570 bool ending_batch_processing_;
572 scoped_ptr<CookiesTreeModel> cookies_tree_model_;
574 DISALLOW_COPY_AND_ASSIGN(SiteDataDeleteHelper);
577 class StorageInfoFetcher :
578 public base::RefCountedThreadSafe<StorageInfoFetcher> {
579 public:
580 StorageInfoFetcher(storage::QuotaManager* quota_manager,
581 const JavaRef<jobject>& java_callback)
582 : env_(base::android::AttachCurrentThread()),
583 quota_manager_(quota_manager),
584 java_callback_(java_callback) {
587 void Run() {
588 // QuotaManager must be called on IO thread, but java_callback must then be
589 // called back on UI thread.
590 BrowserThread::PostTask(
591 BrowserThread::IO, FROM_HERE,
592 base::Bind(&StorageInfoFetcher::GetUsageInfo, this));
595 protected:
596 virtual ~StorageInfoFetcher() {}
598 private:
599 friend class base::RefCountedThreadSafe<StorageInfoFetcher>;
601 void GetUsageInfo() {
602 // We will have no explicit owner as soon as we leave this method.
603 AddRef();
604 quota_manager_->GetUsageInfo(
605 base::Bind(&StorageInfoFetcher::OnGetUsageInfo, this));
608 void OnGetUsageInfo(const storage::UsageInfoEntries& entries) {
609 entries_.insert(entries_.begin(), entries.begin(), entries.end());
610 BrowserThread::PostTask(
611 BrowserThread::UI, FROM_HERE,
612 base::Bind(&StorageInfoFetcher::InvokeCallback, this));
613 Release();
616 void InvokeCallback() {
617 ScopedJavaLocalRef<jobject> list =
618 Java_WebsitePreferenceBridge_createStorageInfoList(env_);
620 storage::UsageInfoEntries::const_iterator i;
621 for (i = entries_.begin(); i != entries_.end(); ++i) {
622 if (i->usage <= 0) continue;
623 ScopedJavaLocalRef<jstring> host =
624 ConvertUTF8ToJavaString(env_, i->host);
626 Java_WebsitePreferenceBridge_insertStorageInfoIntoList(
627 env_, list.obj(), host.obj(), i->type, i->usage);
629 Java_StorageInfoReadyCallback_onStorageInfoReady(
630 env_, java_callback_.obj(), list.obj());
633 JNIEnv* env_;
634 storage::QuotaManager* quota_manager_;
635 ScopedJavaGlobalRef<jobject> java_callback_;
636 storage::UsageInfoEntries entries_;
638 DISALLOW_COPY_AND_ASSIGN(StorageInfoFetcher);
641 class StorageDataDeleter :
642 public base::RefCountedThreadSafe<StorageDataDeleter> {
643 public:
644 StorageDataDeleter(storage::QuotaManager* quota_manager,
645 const std::string& host,
646 storage::StorageType type,
647 const JavaRef<jobject>& java_callback)
648 : env_(base::android::AttachCurrentThread()),
649 quota_manager_(quota_manager),
650 host_(host),
651 type_(type),
652 java_callback_(java_callback) {
655 void Run() {
656 // QuotaManager must be called on IO thread, but java_callback must then be
657 // called back on UI thread. Grant ourself an extra reference to avoid
658 // being deleted after DeleteHostData will return.
659 AddRef();
660 BrowserThread::PostTask(
661 BrowserThread::IO, FROM_HERE,
662 base::Bind(&storage::QuotaManager::DeleteHostData,
663 quota_manager_,
664 host_,
665 type_,
666 storage::QuotaClient::kAllClientsMask,
667 base::Bind(&StorageDataDeleter::OnHostDataDeleted,
668 this)));
671 protected:
672 virtual ~StorageDataDeleter() {}
674 private:
675 friend class base::RefCountedThreadSafe<StorageDataDeleter>;
677 void OnHostDataDeleted(storage::QuotaStatusCode) {
678 DCHECK_CURRENTLY_ON(BrowserThread::IO);
679 quota_manager_->ResetUsageTracker(type_);
680 BrowserThread::PostTask(
681 BrowserThread::UI, FROM_HERE,
682 base::Bind(&StorageDataDeleter::InvokeCallback, this));
683 Release();
686 void InvokeCallback() {
687 Java_StorageInfoClearedCallback_onStorageInfoCleared(
688 env_, java_callback_.obj());
691 JNIEnv* env_;
692 storage::QuotaManager* quota_manager_;
693 std::string host_;
694 storage::StorageType type_;
695 ScopedJavaGlobalRef<jobject> java_callback_;
698 class LocalStorageInfoReadyCallback {
699 public:
700 LocalStorageInfoReadyCallback(
701 const ScopedJavaLocalRef<jobject>& java_callback)
702 : env_(base::android::AttachCurrentThread()),
703 java_callback_(java_callback) {
706 void OnLocalStorageModelInfoLoaded(
707 const std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>&
708 local_storage_info) {
709 ScopedJavaLocalRef<jobject> map =
710 Java_WebsitePreferenceBridge_createLocalStorageInfoMap(env_);
712 std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>::const_iterator
714 for (i = local_storage_info.begin(); i != local_storage_info.end(); ++i) {
715 ScopedJavaLocalRef<jstring> full_origin =
716 ConvertUTF8ToJavaString(env_, i->origin_url.spec());
717 // Remove the trailing backslash so the origin is matched correctly in
718 // SingleWebsitePreferences.mergePermissionInfoForTopLevelOrigin.
719 std::string origin_str = i->origin_url.GetOrigin().spec();
720 DCHECK(origin_str[origin_str.size() - 1] == '/');
721 origin_str = origin_str.substr(0, origin_str.size() - 1);
722 ScopedJavaLocalRef<jstring> origin =
723 ConvertUTF8ToJavaString(env_, origin_str);
724 Java_WebsitePreferenceBridge_insertLocalStorageInfoIntoMap(
725 env_, map.obj(), origin.obj(), full_origin.obj(), i->size);
728 Java_LocalStorageInfoReadyCallback_onLocalStorageInfoReady(
729 env_, java_callback_.obj(), map.obj());
730 delete this;
733 private:
734 JNIEnv* env_;
735 ScopedJavaGlobalRef<jobject> java_callback_;
738 } // anonymous namespace
740 // TODO(jknotten): These methods should not be static. Instead we should
741 // expose a class to Java so that the fetch requests can be cancelled,
742 // and manage the lifetimes of the callback (and indirectly the helper
743 // by having a reference to it).
745 // The helper methods (StartFetching, DeleteLocalStorageFile, DeleteDatabase)
746 // are asynchronous. A "use after free" error is not possible because the
747 // helpers keep a reference to themselves for the duration of their tasks,
748 // which includes callback invocation.
750 static void FetchLocalStorageInfo(JNIEnv* env,
751 const JavaParamRef<jclass>& clazz,
752 const JavaParamRef<jobject>& java_callback) {
753 Profile* profile = ProfileManager::GetActiveUserProfile();
754 scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper(
755 new BrowsingDataLocalStorageHelper(profile));
756 // local_storage_callback will delete itself when it is run.
757 LocalStorageInfoReadyCallback* local_storage_callback =
758 new LocalStorageInfoReadyCallback(
759 ScopedJavaLocalRef<jobject>(env, java_callback));
760 local_storage_helper->StartFetching(
761 base::Bind(&LocalStorageInfoReadyCallback::OnLocalStorageModelInfoLoaded,
762 base::Unretained(local_storage_callback)));
765 static void FetchStorageInfo(JNIEnv* env,
766 const JavaParamRef<jclass>& clazz,
767 const JavaParamRef<jobject>& java_callback) {
768 Profile* profile = ProfileManager::GetActiveUserProfile();
769 scoped_refptr<StorageInfoFetcher> storage_info_fetcher(new StorageInfoFetcher(
770 content::BrowserContext::GetDefaultStoragePartition(
771 profile)->GetQuotaManager(),
772 ScopedJavaLocalRef<jobject>(env, java_callback)));
773 storage_info_fetcher->Run();
776 static void ClearLocalStorageData(JNIEnv* env,
777 const JavaParamRef<jclass>& clazz,
778 const JavaParamRef<jstring>& jorigin) {
779 Profile* profile = ProfileManager::GetActiveUserProfile();
780 scoped_refptr<BrowsingDataLocalStorageHelper> local_storage_helper =
781 new BrowsingDataLocalStorageHelper(profile);
782 GURL origin_url = GURL(ConvertJavaStringToUTF8(env, jorigin));
783 local_storage_helper->DeleteOrigin(origin_url);
786 static void ClearStorageData(JNIEnv* env,
787 const JavaParamRef<jclass>& clazz,
788 const JavaParamRef<jstring>& jhost,
789 jint type,
790 const JavaParamRef<jobject>& java_callback) {
791 Profile* profile = ProfileManager::GetActiveUserProfile();
792 std::string host = ConvertJavaStringToUTF8(env, jhost);
793 scoped_refptr<StorageDataDeleter> storage_data_deleter(new StorageDataDeleter(
794 content::BrowserContext::GetDefaultStoragePartition(
795 profile)->GetQuotaManager(),
796 host,
797 static_cast<storage::StorageType>(type),
798 ScopedJavaLocalRef<jobject>(env, java_callback)));
799 storage_data_deleter->Run();
802 static void ClearCookieData(JNIEnv* env,
803 const JavaParamRef<jclass>& clazz,
804 const JavaParamRef<jstring>& jorigin) {
805 Profile* profile = ProfileManager::GetActiveUserProfile();
806 GURL url(ConvertJavaStringToUTF8(env, jorigin));
807 scoped_refptr<SiteDataDeleteHelper> site_data_deleter(
808 new SiteDataDeleteHelper(profile, url));
809 site_data_deleter->Run();
812 // Register native methods
813 bool RegisterWebsitePreferenceBridge(JNIEnv* env) {
814 return RegisterNativesImpl(env);