blob: 549352fcd490f2cee1601708ad1d54f221183db9 [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/native/aw_quota_manager_bridge_impl.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 "url/gurl.h"
#include "webkit/browser/quota/quota_manager.h"
#include "webkit/common/quota/quota_types.h"
using base::android::AttachCurrentThread;
using content::BrowserThread;
using content::StoragePartition;
using quota::QuotaClient;
using quota::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 AwQuotaManagerBridgeImpl::GetOriginsCallback& callback,
QuotaManager* quota_manager);
void Run();
private:
friend class base::RefCountedThreadSafe<GetOriginsTask>;
~GetOriginsTask();
void OnOriginsObtained(const std::set<GURL>& origins,
quota::StorageType type);
void OnUsageAndQuotaObtained(const GURL& origin,
quota::QuotaStatusCode status_code,
int64 usage,
int64 quota);
void CheckDone();
void DoneOnUIThread();
AwQuotaManagerBridgeImpl::GetOriginsCallback ui_callback_;
scoped_refptr<QuotaManager> quota_manager_;
std::vector<std::string> origin_;
std::vector<int64> usage_;
std::vector<int64> quota_;
size_t num_callbacks_to_wait_;
size_t num_callbacks_received_;
DISALLOW_COPY_AND_ASSIGN(GetOriginsTask);
};
GetOriginsTask::GetOriginsTask(
const AwQuotaManagerBridgeImpl::GetOriginsCallback& callback,
QuotaManager* quota_manager)
: ui_callback_(callback),
quota_manager_(quota_manager) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
GetOriginsTask::~GetOriginsTask() {}
void GetOriginsTask::Run() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&QuotaManager::GetOriginsModifiedSince,
quota_manager_,
quota::kStorageTypeTemporary,
base::Time() /* Since beginning of time. */,
base::Bind(&GetOriginsTask::OnOriginsObtained, this)));
}
void GetOriginsTask::OnOriginsObtained(
const std::set<GURL>& origins, quota::StorageType type) {
DCHECK(BrowserThread::CurrentlyOn(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,
quota::QuotaStatusCode status_code,
int64 usage,
int64 quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (status_code == quota::kQuotaStatusOk) {
origin_.push_back(origin.spec());
usage_.push_back(usage);
quota_.push_back(quota);
}
++num_callbacks_received_;
CheckDone();
}
void GetOriginsTask::CheckDone() {
DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(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
jint GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env, jclass clazz) {
AwBrowserContext* browser_context =
AwContentBrowserClient::GetAwBrowserContext();
AwQuotaManagerBridgeImpl* bridge = static_cast<AwQuotaManagerBridgeImpl*>(
browser_context->GetQuotaManagerBridge());
DCHECK(bridge);
return reinterpret_cast<jint>(bridge);
}
// static
scoped_refptr<AwQuotaManagerBridge> AwQuotaManagerBridgeImpl::Create(
AwBrowserContext* browser_context) {
return new AwQuotaManagerBridgeImpl(browser_context);
}
AwQuotaManagerBridgeImpl::AwQuotaManagerBridgeImpl(
AwBrowserContext* browser_context)
: weak_factory_(this),
browser_context_(browser_context) {
}
AwQuotaManagerBridgeImpl::~AwQuotaManagerBridgeImpl() {}
void AwQuotaManagerBridgeImpl::Init(JNIEnv* env, jobject object) {
java_ref_ = JavaObjectWeakGlobalRef(env, object);
}
StoragePartition* AwQuotaManagerBridgeImpl::GetStoragePartition() const {
DCHECK(BrowserThread::CurrentlyOn(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* AwQuotaManagerBridgeImpl::GetQuotaManager() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
QuotaManager* quota_manager = GetStoragePartition()->GetQuotaManager();
DCHECK(quota_manager);
return quota_manager;
}
void AwQuotaManagerBridgeImpl::DeleteAllData(JNIEnv* env, jobject object) {
RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread,
this));
}
void AwQuotaManagerBridgeImpl::DeleteAllDataOnUiThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GetStoragePartition()->ClearDataForUnboundedRange(
// 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);
}
void AwQuotaManagerBridgeImpl::DeleteOrigin(
JNIEnv* env, jobject object, jstring origin) {
base::string16 origin_string(
base::android::ConvertJavaStringToUTF16(env, origin));
RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread,
this,
origin_string));
}
void AwQuotaManagerBridgeImpl::DeleteOriginOnUiThread(
const base::string16& origin) {
DCHECK(BrowserThread::CurrentlyOn(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());
}
void AwQuotaManagerBridgeImpl::GetOrigins(
JNIEnv* env, jobject object, jint callback_id) {
RunOnUIThread(base::Bind(&AwQuotaManagerBridgeImpl::GetOriginsOnUiThread,
this,
callback_id));
}
void AwQuotaManagerBridgeImpl::GetOriginsOnUiThread(jint callback_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const GetOriginsCallback ui_callback = base::Bind(
&AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl,
weak_factory_.GetWeakPtr(),
callback_id);
(new GetOriginsTask(ui_callback, GetQuotaManager()))->Run();
}
void AwQuotaManagerBridgeImpl::GetOriginsCallbackImpl(
int jcallback_id,
const std::vector<std::string>& origin,
const std::vector<int64>& usage,
const std::vector<int64>& quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AwQuotaManagerBridge_onGetOriginsCallback(
env,
obj.obj(),
jcallback_id,
base::android::ToJavaArrayOfStrings(env, origin).obj(),
base::android::ToJavaLongArray(env, usage).obj(),
base::android::ToJavaLongArray(env, quota).obj());
}
namespace {
void OnUsageAndQuotaObtained(
const AwQuotaManagerBridgeImpl::QuotaUsageCallback& ui_callback,
quota::QuotaStatusCode status_code,
int64 usage,
int64 quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (status_code != quota::kQuotaStatusOk) {
usage = 0;
quota = 0;
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(ui_callback, usage, quota));
}
} // namespace
void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOrigin(
JNIEnv* env, jobject object,
jstring origin,
jint callback_id,
bool is_quota) {
base::string16 origin_string(
base::android::ConvertJavaStringToUTF16(env, origin));
RunOnUIThread(base::Bind(
&AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread,
this,
origin_string,
callback_id,
is_quota));
}
void AwQuotaManagerBridgeImpl::GetUsageAndQuotaForOriginOnUiThread(
const base::string16& origin,
jint callback_id,
bool is_quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const QuotaUsageCallback ui_callback = base::Bind(
&AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl,
weak_factory_.GetWeakPtr(),
callback_id,
is_quota);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&QuotaManager::GetUsageAndQuota,
GetQuotaManager(),
GURL(origin),
quota::kStorageTypeTemporary,
base::Bind(&OnUsageAndQuotaObtained, ui_callback)));
}
void AwQuotaManagerBridgeImpl::QuotaUsageCallbackImpl(
int jcallback_id, bool is_quota, int64 usage, int64 quota) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AwQuotaManagerBridge_onGetUsageAndQuotaForOriginCallback(
env, obj.obj(), jcallback_id, is_quota, usage, quota);
}
bool RegisterAwQuotaManagerBridge(JNIEnv* env) {
return RegisterNativesImpl(env) >= 0;
}
} // namespace android_webview