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 22 using base::android::AttachCurrentThread; 23 using content::BrowserThread; 24 using content::StoragePartition; 25 using quota::QuotaClient; 26 using quota::QuotaManager; 27 28 namespace android_webview { 29 30 namespace { 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. 36 class 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 72 GetOriginsTask::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 80 GetOriginsTask::~GetOriginsTask() {} 81 82 void 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 94 void 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 112 void 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 127 void 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. 140 void GetOriginsTask::DoneOnUIThread() { 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 142 ui_callback_.Run(origin_, usage_, quota_); 143 } 144 145 void 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 157 jlong 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<intptr_t>(bridge); 165 } 166 167 // static 168 scoped_refptr<AwQuotaManagerBridge> AwQuotaManagerBridgeImpl::Create( 169 AwBrowserContext* browser_context) { 170 return new AwQuotaManagerBridgeImpl(browser_context); 171 } 172 173 AwQuotaManagerBridgeImpl::AwQuotaManagerBridgeImpl( 174 AwBrowserContext* browser_context) 175 : weak_factory_(this), 176 browser_context_(browser_context) { 177 } 178 179 AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {} 180 181 void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) { 182 java_ref_ = JavaObjectWeakGlobalRef(env, object); 183 } 184 185 StoragePartition* 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 195 QuotaManager* 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 203 void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) { 204 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread, 205 this)); 206 } 207 208 void AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread() { 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 210 GetStoragePartition()->ClearData( 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 GURL(), StoragePartition::OriginMatcherFunction(), 219 base::Time(), base::Time::Max(), base::Bind(&base::DoNothing)); 220 } 221 222 void AwQuotaManagerBridgeImpl::DeleteOrigin( 223 JNIEnv* env, jobject object, jstring origin) { 224 base::string16 origin_string( 225 base::android::ConvertJavaStringToUTF16(env, origin)); 226 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread, 227 this, 228 origin_string)); 229 } 230 231 void AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread( 232 const base::string16& origin) { 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 234 StoragePartition* storage_partition = GetStoragePartition(); 235 storage_partition->ClearDataForOrigin( 236 // All (temporary) QuotaClient types. 237 StoragePartition::REMOVE_DATA_MASK_APPCACHE | 238 StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | 239 StoragePartition::REMOVE_DATA_MASK_INDEXEDDB | 240 StoragePartition::REMOVE_DATA_MASK_WEBSQL, 241 StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, 242 GURL(origin), 243 storage_partition->GetURLRequestContext()); 244 } 245 246 void AwQuotaManagerBridgeImpl::GetOrigins( 247 JNIEnv* env, jobject object, jint callback_id) { 248 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::GetOriginsOnUiThread, 249 this, 250 callback_id)); 251 } 252 253 void AwQuotaManagerBridgeImpl::GetOriginsOnUiThread(jint callback_id) { 254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 255 256 const GetOriginsCallback ui_callback = base::Bind( 257 &AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl, 258 weak_factory_.GetWeakPtr(), 259 callback_id); 260 261 (new GetOriginsTask(ui_callback, GetQuotaManager()))->Run(); 262 } 263 264 void AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl( 265 int jcallback_id, 266 const std::vector<std::string>& origin, 267 const std::vector<int64>& usage, 268 const std::vector<int64>& quota) { 269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 270 JNIEnv* env = AttachCurrentThread(); 271 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 272 if (obj.is_null()) 273 return; 274 275 Java_AwQuotaManagerBridge_onGetOriginsCallback( 276 env, 277 obj.obj(), 278 jcallback_id, 279 base::android::ToJavaArrayOfStrings(env, origin).obj(), 280 base::android::ToJavaLongArray(env, usage).obj(), 281 base::android::ToJavaLongArray(env, quota).obj()); 282 } 283 284 namespace { 285 286 void OnUsageAndQuotaObtained( 287 const AwQuotaManagerBridgeImpl::QuotaUsageCallback& ui_callback, 288 quota::QuotaStatusCode status_code, 289 int64 usage, 290 int64 quota) { 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 292 if (status_code != quota::kQuotaStatusOk) { 293 usage = 0; 294 quota = 0; 295 } 296 BrowserThread::PostTask( 297 BrowserThread::UI, 298 FROM_HERE, 299 base::Bind(ui_callback, usage, quota)); 300 } 301 302 } // namespace 303 304 void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin( 305 JNIEnv* env, jobject object, 306 jstring origin, 307 jint callback_id, 308 bool is_quota) { 309 base::string16 origin_string( 310 base::android::ConvertJavaStringToUTF16(env, origin)); 311 RunOnUIThread(base::Bind( 312 &AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread, 313 this, 314 origin_string, 315 callback_id, 316 is_quota)); 317 } 318 319 void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread( 320 const base::string16& origin, 321 jint callback_id, 322 bool is_quota) { 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 324 const QuotaUsageCallback ui_callback = base::Bind( 325 &AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl, 326 weak_factory_.GetWeakPtr(), 327 callback_id, 328 is_quota); 329 330 BrowserThread::PostTask( 331 BrowserThread::IO, 332 FROM_HERE, 333 base::Bind(&QuotaManager::GetUsageAndQuota, 334 GetQuotaManager(), 335 GURL(origin), 336 quota::kStorageTypeTemporary, 337 base::Bind(&OnUsageAndQuotaObtained, ui_callback))); 338 } 339 340 void AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl( 341 int jcallback_id, bool is_quota, int64 usage, int64 quota) { 342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 343 JNIEnv* env = AttachCurrentThread(); 344 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 345 if (obj.is_null()) 346 return; 347 348 Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback( 349 env, obj.obj(), jcallback_id, is_quota, usage, quota); 350 } 351 352 bool RegisterAwQuotaManagerBridge(JNIEnv* env) { 353 return RegisterNativesImpl(env); 354 } 355 356 } // namespace android_webview 357