root/android_webview/native/aw_quota_manager_bridge_impl.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Run
  2. OnOriginsObtained
  3. OnUsageAndQuotaObtained
  4. CheckDone
  5. DoneOnUIThread
  6. RunOnUIThread
  7. GetDefaultNativeAwQuotaManagerBridge
  8. Create
  9. browser_context_
  10. Init
  11. GetStoragePartition
  12. GetQuotaManager
  13. DeleteAllData
  14. DeleteAllDataOnUiThread
  15. DeleteOrigin
  16. DeleteOriginOnUiThread
  17. GetOrigins
  18. GetOriginsOnUiThread
  19. GetOriginsCallbackImpl
  20. OnUsageAndQuotaObtained
  21. GetUsageAndQuotaForOrigin
  22. GetUsageAndQuotaForOriginOnUiThread
  23. QuotaUsageCallbackImpl
  24. RegisterAwQuotaManagerBridge

// 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
jlong GetDefaultNativeAwQuotaManagerBridge(JNIEnv* env, jclass clazz) {
  AwBrowserContext* browser_context =
      AwContentBrowserClient::GetAwBrowserContext();

  AwQuotaManagerBridgeImpl* bridge = static_cast<AwQuotaManagerBridgeImpl*>(
      browser_context->GetQuotaManagerBridge());
  DCHECK(bridge);
  return reinterpret_cast<intptr_t>(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()->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 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

/* [<][>][^][v][top][bottom][index][help] */