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 "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