blob: f39c196b334ebadc62dc186b7e74286ed7f4251e [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/aw_quota_manager_bridge.h"
#include <set>
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_content_browser_client.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/synchronization/waitable_event.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "jni/AwQuotaManagerBridge_jni.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/common/quota/quota_types.h"
#include "url/gurl.h"
using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using content::BrowserThread;
using content::StoragePartition;
using storage::QuotaClient;
using storage::QuotaManager;
namespace android_webview {
namespace {
// This object lives on UI and IO threads. Care need to be taken to make sure
// there are no concurrent accesses to instance variables. Also this object
// is refcounted in the various callbacks, and is destroyed when all callbacks
// are destroyed at the end of DoneOnUIThread.
class GetOriginsTask : public base::RefCountedThreadSafe<GetOriginsTask> {
public:
GetOriginsTask(const AwQuotaManagerBridge::GetOriginsCallback& callback,
QuotaManager* quota_manager);
void Run();
private:
friend class base::RefCountedThreadSafe<GetOriginsTask>;
~GetOriginsTask();
void OnOriginsObtained(const std::set<GURL>& origins,
storage::StorageType type);
void OnUsageAndQuotaObtained(const GURL& origin,
storage::QuotaStatusCode status_code,
int64_t usage,
int64_t quota);
void CheckDone();
void DoneOnUIThread();
AwQuotaManagerBridge::GetOriginsCallback ui_callback_;
scoped_refptr<QuotaManager> quota_manager_;
std::vector<std::string> origin_;
std::vector<int64_t> usage_;
std::vector<int64_t> quota_;
size_t num_callbacks_to_wait_;
size_t num_callbacks_received_;
DISALLOW_COPY_AND_ASSIGN(GetOriginsTask);
};
GetOriginsTask::GetOriginsTask(
const AwQuotaManagerBridge::GetOriginsCallback& callback,
QuotaManager* quota_manager)
: ui_callback_(callback), quota_manager_(quota_manager) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
GetOriginsTask::~GetOriginsTask() {}
void GetOriginsTask::Run() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&QuotaManager::GetOriginsModifiedSince, quota_manager_,
storage::kStorageTypeTemporary,
base::Time() /* Since beginning of time. */,
base::Bind(&GetOriginsTask::OnOriginsObtained, this)));
}
void GetOriginsTask::OnOriginsObtained(const std::set<GURL>& origins,
storage::StorageType type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
num_callbacks_to_wait_ = origins.size();
num_callbacks_received_ = 0u;
for (std::set<GURL>::const_iterator origin = origins.begin();
origin != origins.end(); ++origin) {
quota_manager_->GetUsageAndQuota(
*origin, type,
base::Bind(&GetOriginsTask::OnUsageAndQuotaObtained, this, *origin));
}
CheckDone();
}
void GetOriginsTask::OnUsageAndQuotaObtained(
const GURL& origin,
storage::QuotaStatusCode status_code,
int64_t usage,
int64_t quota) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (status_code == storage::kQuotaStatusOk) {
origin_.push_back(origin.spec());
usage_.push_back(usage);
quota_.push_back(quota);
}
++num_callbacks_received_;
CheckDone();
}
void GetOriginsTask::CheckDone() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (num_callbacks_received_ == num_callbacks_to_wait_) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&GetOriginsTask::DoneOnUIThread, this));
} else if (num_callbacks_received_ > num_callbacks_to_wait_) {
NOTREACHED();
}
}
// This method is to avoid copying the 3 vector arguments into a bound callback.
void GetOriginsTask::DoneOnUIThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ui_callback_.Run(origin_, usage_, quota_);
}
void RunOnUIThread(const base::Closure& task) {
if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
task.Run();
} else {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
}
}
} // namespace
// static
jlong GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env,
const JavaParamRef<jclass>& clazz) {
AwBrowserContext* browser_context =
AwContentBrowserClient::GetAwBrowserContext();
AwQuotaManagerBridge* bridge = static_cast<AwQuotaManagerBridge*>(
browser_context->GetQuotaManagerBridge());
DCHECK(bridge);
return reinterpret_cast<intptr_t>(bridge);
}
// static
scoped_refptr<AwQuotaManagerBridge> AwQuotaManagerBridge::Create(
AwBrowserContext* browser_context) {
return new AwQuotaManagerBridge(browser_context);
}
AwQuotaManagerBridge::AwQuotaManagerBridge(AwBrowserContext* browser_context)
: browser_context_(browser_context), weak_factory_(this) {}
AwQuotaManagerBridge::~AwQuotaManagerBridge() {}
void AwQuotaManagerBridge::Init(JNIEnv* env,
const JavaParamRef<jobject>& object) {
java_ref_ = JavaObjectWeakGlobalRef(env, object);
}
StoragePartition* AwQuotaManagerBridge::GetStoragePartition() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// AndroidWebview does not use per-site storage partitions.
StoragePartition* storage_partition =
content::BrowserContext::GetDefaultStoragePartition(browser_context_);
DCHECK(storage_partition);
return storage_partition;
}
QuotaManager* AwQuotaManagerBridge::GetQuotaManager() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
QuotaManager* quota_manager = GetStoragePartition()->GetQuotaManager();
DCHECK(quota_manager);
return quota_manager;
}
void AwQuotaManagerBridge::DeleteAllData(JNIEnv* env,
const JavaParamRef<jobject>& object) {
RunOnUIThread(
base::Bind(&AwQuotaManagerBridge::DeleteAllDataOnUiThread, this));
}
void AwQuotaManagerBridge::DeleteAllDataOnUiThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
GetStoragePartition()->ClearData(
// Clear all web storage data except cookies.
StoragePartition::REMOVE_DATA_MASK_APPCACHE |
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS |
StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE |
StoragePartition::REMOVE_DATA_MASK_WEBSQL,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, GURL(),
StoragePartition::OriginMatcherFunction(), base::Time(),
base::Time::Max(), base::Bind(&base::DoNothing));
}
void AwQuotaManagerBridge::DeleteOrigin(JNIEnv* env,
const JavaParamRef<jobject>& object,
const JavaParamRef<jstring>& origin) {
base::string16 origin_string(
base::android::ConvertJavaStringToUTF16(env, origin));
RunOnUIThread(base::Bind(&AwQuotaManagerBridge::DeleteOriginOnUiThread, this,
origin_string));
}
void AwQuotaManagerBridge::DeleteOriginOnUiThread(
const base::string16& origin) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
StoragePartition* storage_partition = GetStoragePartition();
storage_partition->ClearDataForOrigin(
// All (temporary) QuotaClient types.
StoragePartition::REMOVE_DATA_MASK_APPCACHE |
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS |
StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
StoragePartition::REMOVE_DATA_MASK_WEBSQL,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY, GURL(origin),
storage_partition->GetURLRequestContext(), base::Bind(&base::DoNothing));
}
void AwQuotaManagerBridge::GetOrigins(JNIEnv* env,
const JavaParamRef<jobject>& object,
jint callback_id) {
RunOnUIThread(base::Bind(&AwQuotaManagerBridge::GetOriginsOnUiThread, this,
callback_id));
}
void AwQuotaManagerBridge::GetOriginsOnUiThread(jint callback_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const GetOriginsCallback ui_callback =
base::Bind(&AwQuotaManagerBridge::GetOriginsCallbackImpl,
weak_factory_.GetWeakPtr(), callback_id);
(new GetOriginsTask(ui_callback, GetQuotaManager()))->Run();
}
void AwQuotaManagerBridge::GetOriginsCallbackImpl(
int jcallback_id,
const std::vector<std::string>& origin,
const std::vector<int64_t>& usage,
const std::vector<int64_t>& quota) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AwQuotaManagerBridge_onGetOriginsCallback(
env, obj, jcallback_id, base::android::ToJavaArrayOfStrings(env, origin),
base::android::ToJavaLongArray(env, usage),
base::android::ToJavaLongArray(env, quota));
}
namespace {
void OnUsageAndQuotaObtained(
const AwQuotaManagerBridge::QuotaUsageCallback& ui_callback,
storage::QuotaStatusCode status_code,
int64_t usage,
int64_t quota) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (status_code != storage::kQuotaStatusOk) {
usage = 0;
quota = 0;
}
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(ui_callback, usage, quota));
}
} // namespace
void AwQuotaManagerBridge::GetUsageAndQuotaForOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& object,
const JavaParamRef<jstring>& origin,
jint callback_id,
bool is_quota) {
base::string16 origin_string(
base::android::ConvertJavaStringToUTF16(env, origin));
RunOnUIThread(
base::Bind(&AwQuotaManagerBridge::GetUsageAndQuotaForOriginOnUiThread,
this, origin_string, callback_id, is_quota));
}
void AwQuotaManagerBridge::GetUsageAndQuotaForOriginOnUiThread(
const base::string16& origin,
jint callback_id,
bool is_quota) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const QuotaUsageCallback ui_callback =
base::Bind(&AwQuotaManagerBridge::QuotaUsageCallbackImpl,
weak_factory_.GetWeakPtr(), callback_id, is_quota);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&QuotaManager::GetUsageAndQuota, GetQuotaManager(),
GURL(origin), storage::kStorageTypeTemporary,
base::Bind(&OnUsageAndQuotaObtained, ui_callback)));
}
void AwQuotaManagerBridge::QuotaUsageCallbackImpl(int jcallback_id,
bool is_quota,
int64_t usage,
int64_t quota) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback(
env, obj, jcallback_id, is_quota, usage, quota);
}
} // namespace android_webview