1// Copyright (c) 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 "android_webview/native/aw_quota_manager_bridge_impl.h" 6 7#include <set> 8 9#include "android_webview/browser/aw_browser_context.h" 10#include "android_webview/browser/aw_content_browser_client.h" 11#include "base/android/jni_array.h" 12#include "base/android/jni_string.h" 13#include "base/synchronization/waitable_event.h" 14#include "content/public/browser/browser_thread.h" 15#include "content/public/browser/storage_partition.h" 16#include "content/public/common/content_client.h" 17#include "jni/AwQuotaManagerBridge_jni.h" 18#include "url/gurl.h" 19#include "webkit/browser/quota/quota_manager.h" 20#include "webkit/common/quota/quota_types.h" 21 22using base::android::AttachCurrentThread; 23using content::BrowserThread; 24using content::StoragePartition; 25using quota::QuotaClient; 26using quota::QuotaManager; 27 28namespace android_webview { 29 30namespace { 31 32// This object lives on UI and IO threads. Care need to be taken to make sure 33// there are no concurrent accesses to instance variables. Also this object 34// is refcounted in the various callbacks, and is destroyed when all callbacks 35// are destroyed at the end of DoneOnUIThread. 36class GetOriginsTask : public base::RefCountedThreadSafe<GetOriginsTask> { 37 public: 38 GetOriginsTask( 39 const AwQuotaManagerBridgeImpl::GetOriginsCallback& callback, 40 QuotaManager* quota_manager); 41 42 void Run(); 43 44 private: 45 friend class base::RefCountedThreadSafe<GetOriginsTask>; 46 ~GetOriginsTask(); 47 48 void OnOriginsObtained(const std::set<GURL>& origins, 49 quota::StorageType type); 50 51 void OnUsageAndQuotaObtained(const GURL& origin, 52 quota::QuotaStatusCode status_code, 53 int64 usage, 54 int64 quota); 55 56 void CheckDone(); 57 void DoneOnUIThread(); 58 59 AwQuotaManagerBridgeImpl::GetOriginsCallback ui_callback_; 60 scoped_refptr<QuotaManager> quota_manager_; 61 62 std::vector<std::string> origin_; 63 std::vector<int64> usage_; 64 std::vector<int64> quota_; 65 66 size_t num_callbacks_to_wait_; 67 size_t num_callbacks_received_; 68 69 DISALLOW_COPY_AND_ASSIGN(GetOriginsTask); 70}; 71 72GetOriginsTask::GetOriginsTask( 73 const AwQuotaManagerBridgeImpl::GetOriginsCallback& callback, 74 QuotaManager* quota_manager) 75 : ui_callback_(callback), 76 quota_manager_(quota_manager) { 77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 78} 79 80GetOriginsTask::~GetOriginsTask() {} 81 82void GetOriginsTask::Run() { 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 84 BrowserThread::PostTask( 85 BrowserThread::IO, 86 FROM_HERE, 87 base::Bind(&QuotaManager::GetOriginsModifiedSince, 88 quota_manager_, 89 quota::kStorageTypeTemporary, 90 base::Time() /* Since beginning of time. */, 91 base::Bind(&GetOriginsTask::OnOriginsObtained, this))); 92} 93 94void GetOriginsTask::OnOriginsObtained( 95 const std::set<GURL>& origins, quota::StorageType type) { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 97 num_callbacks_to_wait_ = origins.size(); 98 num_callbacks_received_ = 0u; 99 100 for (std::set<GURL>::const_iterator origin = origins.begin(); 101 origin != origins.end(); 102 ++origin) { 103 quota_manager_->GetUsageAndQuota( 104 *origin, 105 type, 106 base::Bind(&GetOriginsTask::OnUsageAndQuotaObtained, this, *origin)); 107 } 108 109 CheckDone(); 110} 111 112void GetOriginsTask::OnUsageAndQuotaObtained(const GURL& origin, 113 quota::QuotaStatusCode status_code, 114 int64 usage, 115 int64 quota) { 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 117 if (status_code == quota::kQuotaStatusOk) { 118 origin_.push_back(origin.spec()); 119 usage_.push_back(usage); 120 quota_.push_back(quota); 121 } 122 123 ++num_callbacks_received_; 124 CheckDone(); 125} 126 127void GetOriginsTask::CheckDone() { 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 129 if (num_callbacks_received_ == num_callbacks_to_wait_) { 130 BrowserThread::PostTask( 131 BrowserThread::UI, 132 FROM_HERE, 133 base::Bind(&GetOriginsTask::DoneOnUIThread, this)); 134 } else if (num_callbacks_received_ > num_callbacks_to_wait_) { 135 NOTREACHED(); 136 } 137} 138 139// This method is to avoid copying the 3 vector arguments into a bound callback. 140void GetOriginsTask::DoneOnUIThread() { 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 142 ui_callback_.Run(origin_, usage_, quota_); 143} 144 145void RunOnUIThread(const base::Closure& task) { 146 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 147 task.Run(); 148 } else { 149 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task); 150 } 151} 152 153} // namespace 154 155 156// static 157jint GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env, jclass clazz) { 158 AwBrowserContext* browser_context = 159 AwContentBrowserClient::GetAwBrowserContext(); 160 161 AwQuotaManagerBridgeImpl* bridge = static_cast<AwQuotaManagerBridgeImpl*>( 162 browser_context->GetQuotaManagerBridge()); 163 DCHECK(bridge); 164 return reinterpret_cast<jint>(bridge); 165} 166 167// static 168scoped_refptr<AwQuotaManagerBridge> AwQuotaManagerBridgeImpl::Create( 169 AwBrowserContext* browser_context) { 170 return new AwQuotaManagerBridgeImpl(browser_context); 171} 172 173AwQuotaManagerBridgeImpl::AwQuotaManagerBridgeImpl( 174 AwBrowserContext* browser_context) 175 : weak_factory_(this), 176 browser_context_(browser_context) { 177} 178 179AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {} 180 181void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) { 182 java_ref_ = JavaObjectWeakGlobalRef(env, object); 183} 184 185StoragePartition* AwQuotaManagerBridgeImpl::GetStoragePartition() const { 186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 187 188 // AndroidWebview does not use per-site storage partitions. 189 StoragePartition* storage_partition = 190 content::BrowserContext::GetDefaultStoragePartition(browser_context_); 191 DCHECK(storage_partition); 192 return storage_partition; 193} 194 195QuotaManager* AwQuotaManagerBridgeImpl::GetQuotaManager() const { 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 197 198 QuotaManager* quota_manager = GetStoragePartition()->GetQuotaManager(); 199 DCHECK(quota_manager); 200 return quota_manager; 201} 202 203void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) { 204 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread, 205 this)); 206} 207 208void AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread() { 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 210 GetStoragePartition()->ClearDataForUnboundedRange( 211 // Clear all web storage data except cookies. 212 StoragePartition::REMOVE_DATA_MASK_APPCACHE | 213 StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | 214 StoragePartition::REMOVE_DATA_MASK_INDEXEDDB | 215 StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE | 216 StoragePartition::REMOVE_DATA_MASK_WEBSQL, 217 StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY); 218} 219 220void AwQuotaManagerBridgeImpl::DeleteOrigin( 221 JNIEnv* env, jobject object, jstring origin) { 222 base::string16 origin_string( 223 base::android::ConvertJavaStringToUTF16(env, origin)); 224 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread, 225 this, 226 origin_string)); 227} 228 229void AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread( 230 const base::string16& origin) { 231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 232 StoragePartition* storage_partition = GetStoragePartition(); 233 storage_partition->ClearDataForOrigin( 234 // All (temporary) QuotaClient types. 235 StoragePartition::REMOVE_DATA_MASK_APPCACHE | 236 StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | 237 StoragePartition::REMOVE_DATA_MASK_INDEXEDDB | 238 StoragePartition::REMOVE_DATA_MASK_WEBSQL, 239 StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, 240 GURL(origin), 241 storage_partition->GetURLRequestContext()); 242} 243 244void AwQuotaManagerBridgeImpl::GetOrigins( 245 JNIEnv* env, jobject object, jint callback_id) { 246 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::GetOriginsOnUiThread, 247 this, 248 callback_id)); 249} 250 251void AwQuotaManagerBridgeImpl::GetOriginsOnUiThread(jint callback_id) { 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 254 const GetOriginsCallback ui_callback = base::Bind( 255 &AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl, 256 weak_factory_.GetWeakPtr(), 257 callback_id); 258 259 (new GetOriginsTask(ui_callback, GetQuotaManager()))->Run(); 260} 261 262void AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl( 263 int jcallback_id, 264 const std::vector<std::string>& origin, 265 const std::vector<int64>& usage, 266 const std::vector<int64>& quota) { 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 268 JNIEnv* env = AttachCurrentThread(); 269 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 270 if (obj.is_null()) 271 return; 272 273 Java_AwQuotaManagerBridge_onGetOriginsCallback( 274 env, 275 obj.obj(), 276 jcallback_id, 277 base::android::ToJavaArrayOfStrings(env, origin).obj(), 278 base::android::ToJavaLongArray(env, usage).obj(), 279 base::android::ToJavaLongArray(env, quota).obj()); 280} 281 282namespace { 283 284void OnUsageAndQuotaObtained( 285 const AwQuotaManagerBridgeImpl::QuotaUsageCallback& ui_callback, 286 quota::QuotaStatusCode status_code, 287 int64 usage, 288 int64 quota) { 289 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 290 if (status_code != quota::kQuotaStatusOk) { 291 usage = 0; 292 quota = 0; 293 } 294 BrowserThread::PostTask( 295 BrowserThread::UI, 296 FROM_HERE, 297 base::Bind(ui_callback, usage, quota)); 298} 299 300} // namespace 301 302void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin( 303 JNIEnv* env, jobject object, 304 jstring origin, 305 jint callback_id, 306 bool is_quota) { 307 base::string16 origin_string( 308 base::android::ConvertJavaStringToUTF16(env, origin)); 309 RunOnUIThread(base::Bind( 310 &AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread, 311 this, 312 origin_string, 313 callback_id, 314 is_quota)); 315} 316 317void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread( 318 const base::string16& origin, 319 jint callback_id, 320 bool is_quota) { 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 322 const QuotaUsageCallback ui_callback = base::Bind( 323 &AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl, 324 weak_factory_.GetWeakPtr(), 325 callback_id, 326 is_quota); 327 328 BrowserThread::PostTask( 329 BrowserThread::IO, 330 FROM_HERE, 331 base::Bind(&QuotaManager::GetUsageAndQuota, 332 GetQuotaManager(), 333 GURL(origin), 334 quota::kStorageTypeTemporary, 335 base::Bind(&OnUsageAndQuotaObtained, ui_callback))); 336} 337 338void AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl( 339 int jcallback_id, bool is_quota, int64 usage, int64 quota) { 340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 341 JNIEnv* env = AttachCurrentThread(); 342 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 343 if (obj.is_null()) 344 return; 345 346 Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback( 347 env, obj.obj(), jcallback_id, is_quota, usage, quota); 348} 349 350bool RegisterAwQuotaManagerBridge(JNIEnv* env) { 351 return RegisterNativesImpl(env) >= 0; 352} 353 354} // namespace android_webview 355