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 "storage/browser/quota/quota_manager.h" 19 #include "storage/common/quota/quota_types.h" 20 #include "url/gurl.h" 21 22 using base::android::AttachCurrentThread; 23 using content::BrowserThread; 24 using content::StoragePartition; 25 using storage::QuotaClient; 26 using storage::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 storage::StorageType type); 50 51 void OnUsageAndQuotaObtained(const GURL& origin, 52 storage::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 storage::kStorageTypeTemporary, 90 base::Time() /* Since beginning of time. */, 91 base::Bind(&GetOriginsTask::OnOriginsObtained, this))); 92 } 93 94 void GetOriginsTask::OnOriginsObtained(const std::set<GURL>& origins, 95 storage::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( 113 const GURL& origin, 114 storage::QuotaStatusCode status_code, 115 int64 usage, 116 int64 quota) { 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 118 if (status_code == storage::kQuotaStatusOk) { 119 origin_.push_back(origin.spec()); 120 usage_.push_back(usage); 121 quota_.push_back(quota); 122 } 123 124 ++num_callbacks_received_; 125 CheckDone(); 126 } 127 128 void GetOriginsTask::CheckDone() { 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 130 if (num_callbacks_received_ == num_callbacks_to_wait_) { 131 BrowserThread::PostTask( 132 BrowserThread::UI, 133 FROM_HERE, 134 base::Bind(&GetOriginsTask::DoneOnUIThread, this)); 135 } else if (num_callbacks_received_ > num_callbacks_to_wait_) { 136 NOTREACHED(); 137 } 138 } 139 140 // This method is to avoid copying the 3 vector arguments into a bound callback. 141 void GetOriginsTask::DoneOnUIThread() { 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 143 ui_callback_.Run(origin_, usage_, quota_); 144 } 145 146 void RunOnUIThread(const base::Closure& task) { 147 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 148 task.Run(); 149 } else { 150 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task); 151 } 152 } 153 154 } // namespace 155 156 157 // static 158 jlong GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env, jclass clazz) { 159 AwBrowserContext* browser_context = 160 AwContentBrowserClient::GetAwBrowserContext(); 161 162 AwQuotaManagerBridgeImpl* bridge = static_cast<AwQuotaManagerBridgeImpl*>( 163 browser_context->GetQuotaManagerBridge()); 164 DCHECK(bridge); 165 return reinterpret_cast<intptr_t>(bridge); 166 } 167 168 // static 169 scoped_refptr<AwQuotaManagerBridge> AwQuotaManagerBridgeImpl::Create( 170 AwBrowserContext* browser_context) { 171 return new AwQuotaManagerBridgeImpl(browser_context); 172 } 173 174 AwQuotaManagerBridgeImpl::AwQuotaManagerBridgeImpl( 175 AwBrowserContext* browser_context) 176 : browser_context_(browser_context), 177 weak_factory_(this) { 178 } 179 180 AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {} 181 182 void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) { 183 java_ref_ = JavaObjectWeakGlobalRef(env, object); 184 } 185 186 StoragePartition* AwQuotaManagerBridgeImpl::GetStoragePartition() const { 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 188 189 // AndroidWebview does not use per-site storage partitions. 190 StoragePartition* storage_partition = 191 content::BrowserContext::GetDefaultStoragePartition(browser_context_); 192 DCHECK(storage_partition); 193 return storage_partition; 194 } 195 196 QuotaManager* AwQuotaManagerBridgeImpl::GetQuotaManager() const { 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 199 QuotaManager* quota_manager = GetStoragePartition()->GetQuotaManager(); 200 DCHECK(quota_manager); 201 return quota_manager; 202 } 203 204 void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) { 205 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread, 206 this)); 207 } 208 209 void AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread() { 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 211 GetStoragePartition()->ClearData( 212 // Clear all web storage data except cookies. 213 StoragePartition::REMOVE_DATA_MASK_APPCACHE | 214 StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | 215 StoragePartition::REMOVE_DATA_MASK_INDEXEDDB | 216 StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE | 217 StoragePartition::REMOVE_DATA_MASK_WEBSQL, 218 StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, 219 GURL(), StoragePartition::OriginMatcherFunction(), 220 base::Time(), base::Time::Max(), base::Bind(&base::DoNothing)); 221 } 222 223 void AwQuotaManagerBridgeImpl::DeleteOrigin( 224 JNIEnv* env, jobject object, jstring origin) { 225 base::string16 origin_string( 226 base::android::ConvertJavaStringToUTF16(env, origin)); 227 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread, 228 this, 229 origin_string)); 230 } 231 232 void AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread( 233 const base::string16& origin) { 234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 235 StoragePartition* storage_partition = GetStoragePartition(); 236 storage_partition->ClearDataForOrigin( 237 // All (temporary) QuotaClient types. 238 StoragePartition::REMOVE_DATA_MASK_APPCACHE | 239 StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS | 240 StoragePartition::REMOVE_DATA_MASK_INDEXEDDB | 241 StoragePartition::REMOVE_DATA_MASK_WEBSQL, 242 StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, 243 GURL(origin), 244 storage_partition->GetURLRequestContext(), 245 base::Bind(&base::DoNothing)); 246 } 247 248 void AwQuotaManagerBridgeImpl::GetOrigins( 249 JNIEnv* env, jobject object, jint callback_id) { 250 RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::GetOriginsOnUiThread, 251 this, 252 callback_id)); 253 } 254 255 void AwQuotaManagerBridgeImpl::GetOriginsOnUiThread(jint callback_id) { 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 258 const GetOriginsCallback ui_callback = base::Bind( 259 &AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl, 260 weak_factory_.GetWeakPtr(), 261 callback_id); 262 263 (new GetOriginsTask(ui_callback, GetQuotaManager()))->Run(); 264 } 265 266 void AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl( 267 int jcallback_id, 268 const std::vector<std::string>& origin, 269 const std::vector<int64>& usage, 270 const std::vector<int64>& quota) { 271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 272 JNIEnv* env = AttachCurrentThread(); 273 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 274 if (obj.is_null()) 275 return; 276 277 Java_AwQuotaManagerBridge_onGetOriginsCallback( 278 env, 279 obj.obj(), 280 jcallback_id, 281 base::android::ToJavaArrayOfStrings(env, origin).obj(), 282 base::android::ToJavaLongArray(env, usage).obj(), 283 base::android::ToJavaLongArray(env, quota).obj()); 284 } 285 286 namespace { 287 288 void OnUsageAndQuotaObtained( 289 const AwQuotaManagerBridgeImpl::QuotaUsageCallback& ui_callback, 290 storage::QuotaStatusCode status_code, 291 int64 usage, 292 int64 quota) { 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 294 if (status_code != storage::kQuotaStatusOk) { 295 usage = 0; 296 quota = 0; 297 } 298 BrowserThread::PostTask( 299 BrowserThread::UI, 300 FROM_HERE, 301 base::Bind(ui_callback, usage, quota)); 302 } 303 304 } // namespace 305 306 void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin( 307 JNIEnv* env, jobject object, 308 jstring origin, 309 jint callback_id, 310 bool is_quota) { 311 base::string16 origin_string( 312 base::android::ConvertJavaStringToUTF16(env, origin)); 313 RunOnUIThread(base::Bind( 314 &AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread, 315 this, 316 origin_string, 317 callback_id, 318 is_quota)); 319 } 320 321 void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread( 322 const base::string16& origin, 323 jint callback_id, 324 bool is_quota) { 325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 326 const QuotaUsageCallback ui_callback = base::Bind( 327 &AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl, 328 weak_factory_.GetWeakPtr(), 329 callback_id, 330 is_quota); 331 332 BrowserThread::PostTask( 333 BrowserThread::IO, 334 FROM_HERE, 335 base::Bind(&QuotaManager::GetUsageAndQuota, 336 GetQuotaManager(), 337 GURL(origin), 338 storage::kStorageTypeTemporary, 339 base::Bind(&OnUsageAndQuotaObtained, ui_callback))); 340 } 341 342 void AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl( 343 int jcallback_id, bool is_quota, int64 usage, int64 quota) { 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 345 JNIEnv* env = AttachCurrentThread(); 346 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 347 if (obj.is_null()) 348 return; 349 350 Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback( 351 env, obj.obj(), jcallback_id, is_quota, usage, quota); 352 } 353 354 bool RegisterAwQuotaManagerBridge(JNIEnv* env) { 355 return RegisterNativesImpl(env); 356 } 357 358 } // namespace android_webview 359