Home | History | Annotate | Download | only in native
      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