1 // Copyright 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.
5 #include "webkit/browser/quota/quota_manager.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/file_util.h"
17 #include "base/files/file_path.h"
18 #include "base/metrics/histogram.h"
19 #include "base/sequenced_task_runner.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/sys_info.h"
23 #include "base/task_runner_util.h"
24 #include "base/time/time.h"
25 #include "net/base/net_util.h"
26 #include "webkit/browser/quota/quota_database.h"
27 #include "webkit/browser/quota/quota_temporary_storage_evictor.h"
28 #include "webkit/browser/quota/usage_tracker.h"
29 #include "webkit/common/quota/quota_types.h"
31 #define UMA_HISTOGRAM_MBYTES(name, sample) \
32 UMA_HISTOGRAM_CUSTOM_COUNTS( \
33 (name), static_cast<int>((sample) / kMBytes), \
34 1, 10 * 1024 * 1024 /* 10TB */, 100)
40 const int64 kMBytes = 1024 * 1024;
41 const int kMinutesInMilliSeconds = 60 * 1000;
43 const int64 kReportHistogramInterval = 60 * 60 * 1000; // 1 hour
44 const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0; // 33%
48 // Arbitrary for now, but must be reasonably small so that
49 // in-memory databases can fit.
50 // TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this.
51 const int64 QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes;
53 const int64 QuotaManager::kNoLimit = kint64max;
55 const int QuotaManager::kPerHostTemporaryPortion = 5; // 20%
57 const char QuotaManager::kDatabaseName[] = "QuotaManager";
59 // Preserve kMinimumPreserveForSystem disk space for system book-keeping
60 // when returning the quota to unlimited apps/extensions.
61 // TODO(kinuko): This should be like 10% of the actual disk space.
62 // For now we simply use a constant as getting the disk size needs
63 // platform-dependent code. (http://crbug.com/178976)
64 const int64 QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes;
66 const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3;
68 const int QuotaManager::kEvictionIntervalInMilliSeconds =
69 30 * kMinutesInMilliSeconds;
71 // Heuristics: assuming average cloud server allows a few Gigs storage
72 // on the server side and the storage needs to be shared for user data
73 // and by multiple apps.
74 int64 QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes;
78 void CountOriginType(const std::set<GURL>& origins,
79 SpecialStoragePolicy* policy,
80 size_t* protected_origins,
81 size_t* unlimited_origins) {
82 DCHECK(protected_origins);
83 DCHECK(unlimited_origins);
84 *protected_origins = 0;
85 *unlimited_origins = 0;
88 for (std::set<GURL>::const_iterator itr = origins.begin();
91 if (policy->IsStorageProtected(*itr))
93 if (policy->IsStorageUnlimited(*itr))
98 bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64* new_quota,
99 QuotaDatabase* database) {
101 if (!database->SetQuotaConfigValue(
102 QuotaDatabase::kTemporaryQuotaOverrideKey, *new_quota)) {
109 bool GetPersistentHostQuotaOnDBThread(const std::string& host,
111 QuotaDatabase* database) {
113 database->GetHostQuota(host, kStorageTypePersistent, quota);
117 bool SetPersistentHostQuotaOnDBThread(const std::string& host,
119 QuotaDatabase* database) {
121 if (database->SetHostQuota(host, kStorageTypePersistent, *new_quota))
127 bool InitializeOnDBThread(int64* temporary_quota_override,
128 int64* desired_available_space,
129 QuotaDatabase* database) {
131 database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey,
132 temporary_quota_override);
133 database->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey,
134 desired_available_space);
138 bool GetLRUOriginOnDBThread(StorageType type,
139 std::set<GURL>* exceptions,
140 SpecialStoragePolicy* policy,
142 QuotaDatabase* database) {
144 database->GetLRUOrigin(type, *exceptions, policy, url);
148 bool DeleteOriginInfoOnDBThread(const GURL& origin,
150 QuotaDatabase* database) {
152 return database->DeleteOriginInfo(origin, type);
155 bool InitializeTemporaryOriginsInfoOnDBThread(const std::set<GURL>* origins,
156 QuotaDatabase* database) {
158 if (database->IsOriginDatabaseBootstrapped())
161 // Register existing origins with 0 last time access.
162 if (database->RegisterInitialOriginInfo(*origins, kStorageTypeTemporary)) {
163 database->SetOriginDatabaseBootstrapped(true);
169 bool UpdateAccessTimeOnDBThread(const GURL& origin,
171 base::Time accessed_time,
172 QuotaDatabase* database) {
174 return database->SetOriginLastAccessTime(origin, type, accessed_time);
177 bool UpdateModifiedTimeOnDBThread(const GURL& origin,
179 base::Time modified_time,
180 QuotaDatabase* database) {
182 return database->SetOriginLastModifiedTime(origin, type, modified_time);
185 int64 CallSystemGetAmountOfFreeDiskSpace(const base::FilePath& profile_path) {
186 // Ensure the profile path exists.
187 if(!file_util::CreateDirectory(profile_path)) {
188 LOG(WARNING) << "Create directory failed for path" << profile_path.value();
191 return base::SysInfo::AmountOfFreeDiskSpace(profile_path);
194 int64 CalculateTemporaryGlobalQuota(int64 global_limited_usage,
195 int64 available_space) {
196 DCHECK_GE(global_limited_usage, 0);
197 int64 avail_space = available_space;
198 if (avail_space < kint64max - global_limited_usage) {
199 // We basically calculate the temporary quota by
200 // [available_space + space_used_for_temp] * kTempQuotaRatio,
201 // but make sure we'll have no overflow.
202 avail_space += global_limited_usage;
204 return avail_space * kTemporaryQuotaRatioToAvail;
207 void DispatchTemporaryGlobalQuotaCallback(
208 const QuotaCallback& callback,
209 QuotaStatusCode status,
210 const UsageAndQuota& usage_and_quota) {
211 if (status != kQuotaStatusOk) {
212 callback.Run(status, 0);
216 callback.Run(status, CalculateTemporaryGlobalQuota(
217 usage_and_quota.global_limited_usage,
218 usage_and_quota.available_disk_space));
221 int64 CalculateQuotaWithDiskSpace(
222 int64 available_disk_space, int64 usage, int64 quota) {
223 if (available_disk_space < QuotaManager::kMinimumPreserveForSystem ||
225 // No more space; cap the quota to the current usage.
229 available_disk_space -= QuotaManager::kMinimumPreserveForSystem;
230 if (available_disk_space < quota - usage)
231 return available_disk_space + usage;
236 int64 CalculateTemporaryHostQuota(int64 host_usage,
238 int64 global_limited_usage) {
239 DCHECK_GE(global_limited_usage, 0);
240 int64 host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion;
241 if (global_limited_usage > global_quota)
242 host_quota = std::min(host_quota, host_usage);
246 void DispatchUsageAndQuotaForWebApps(
250 bool can_query_disk_size,
251 const QuotaManager::GetUsageAndQuotaCallback& callback,
252 QuotaStatusCode status,
253 const UsageAndQuota& usage_and_quota) {
254 if (status != kQuotaStatusOk) {
255 callback.Run(status, 0, 0);
259 int64 usage = usage_and_quota.usage;
260 int64 quota = usage_and_quota.quota;
262 if (type == kStorageTypeTemporary && !is_unlimited) {
263 quota = CalculateTemporaryHostQuota(
264 usage, quota, usage_and_quota.global_limited_usage);
268 quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit);
269 callback.Run(status, usage, quota);
273 // For apps with unlimited permission or can_query_disk_size is true (and not
274 // in incognito mode).
275 // We assume we can expose the actual disk size for them and cap the quota by
276 // the available disk space.
277 if (is_unlimited || can_query_disk_size) {
280 CalculateQuotaWithDiskSpace(
281 usage_and_quota.available_disk_space,
286 callback.Run(status, usage, quota);
291 UsageAndQuota::UsageAndQuota()
293 global_limited_usage(0),
295 available_disk_space(0) {
298 UsageAndQuota::UsageAndQuota(
300 int64 global_limited_usage,
302 int64 available_disk_space)
304 global_limited_usage(global_limited_usage),
306 available_disk_space(available_disk_space) {
309 class UsageAndQuotaCallbackDispatcher
311 public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> {
313 UsageAndQuotaCallbackDispatcher(QuotaManager* manager)
314 : QuotaTask(manager),
316 has_global_limited_usage_(false),
318 has_available_disk_space_(false),
319 status_(kQuotaStatusUnknown),
320 usage_and_quota_(-1, -1, -1, -1),
321 waiting_callbacks_(1) {}
323 virtual ~UsageAndQuotaCallbackDispatcher() {}
325 void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) {
326 callback_ = callback;
330 void set_usage(int64 usage) {
331 usage_and_quota_.usage = usage;
335 void set_global_limited_usage(int64 global_limited_usage) {
336 usage_and_quota_.global_limited_usage = global_limited_usage;
337 has_global_limited_usage_ = true;
340 void set_quota(int64 quota) {
341 usage_and_quota_.quota = quota;
345 void set_available_disk_space(int64 available_disk_space) {
346 usage_and_quota_.available_disk_space = available_disk_space;
347 has_available_disk_space_ = true;
350 UsageCallback GetHostUsageCallback() {
351 ++waiting_callbacks_;
353 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage,
357 UsageCallback GetGlobalLimitedUsageCallback() {
358 ++waiting_callbacks_;
359 has_global_limited_usage_ = true;
361 &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage,
365 QuotaCallback GetQuotaCallback() {
366 ++waiting_callbacks_;
368 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota,
372 QuotaCallback GetAvailableSpaceCallback() {
373 ++waiting_callbacks_;
374 has_available_disk_space_ = true;
375 return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace,
380 void DidGetHostUsage(int64 usage) {
381 if (status_ == kQuotaStatusUnknown)
382 status_ = kQuotaStatusOk;
383 usage_and_quota_.usage = usage;
387 void DidGetGlobalLimitedUsage(int64 limited_usage) {
388 if (status_ == kQuotaStatusUnknown)
389 status_ = kQuotaStatusOk;
390 usage_and_quota_.global_limited_usage = limited_usage;
394 void DidGetQuota(QuotaStatusCode status, int64 quota) {
395 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
397 usage_and_quota_.quota = quota;
401 void DidGetAvailableSpace(QuotaStatusCode status, int64 space) {
403 if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk)
405 usage_and_quota_.available_disk_space = space;
409 virtual void Run() OVERRIDE {
410 // We initialize waiting_callbacks to 1 so that we won't run
411 // the completion callback until here even some of the callbacks
412 // are dispatched synchronously.
416 virtual void Aborted() OVERRIDE {
417 callback_.Run(kQuotaErrorAbort, UsageAndQuota());
421 virtual void Completed() OVERRIDE {
422 DCHECK(!has_usage_ || usage_and_quota_.usage >= 0);
423 DCHECK(!has_global_limited_usage_ ||
424 usage_and_quota_.global_limited_usage >= 0);
425 DCHECK(!has_quota_ || usage_and_quota_.quota >= 0);
426 DCHECK(!has_available_disk_space_ ||
427 usage_and_quota_.available_disk_space >= 0);
429 callback_.Run(status_, usage_and_quota_);
433 void CheckCompleted() {
434 if (--waiting_callbacks_ <= 0)
438 // For sanity checks, they're checked only when DCHECK is on.
440 bool has_global_limited_usage_;
442 bool has_available_disk_space_;
444 QuotaStatusCode status_;
445 UsageAndQuota usage_and_quota_;
446 QuotaManager::UsageAndQuotaCallback callback_;
447 int waiting_callbacks_;
449 DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher);
452 class QuotaManager::GetUsageInfoTask : public QuotaTask {
454 typedef QuotaManager::GetUsageInfoTask self_type;
458 QuotaManager* manager,
459 const GetUsageInfoCallback& callback)
460 : QuotaTask(manager),
462 weak_factory_(this) {
466 virtual void Run() OVERRIDE {
467 remaining_trackers_ = 3;
468 // This will populate cached hosts and usage info.
469 manager()->GetUsageTracker(kStorageTypeTemporary)->GetGlobalUsage(
470 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
471 weak_factory_.GetWeakPtr(),
472 kStorageTypeTemporary));
473 manager()->GetUsageTracker(kStorageTypePersistent)->GetGlobalUsage(
474 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
475 weak_factory_.GetWeakPtr(),
476 kStorageTypePersistent));
477 manager()->GetUsageTracker(kStorageTypeSyncable)->GetGlobalUsage(
478 base::Bind(&GetUsageInfoTask::DidGetGlobalUsage,
479 weak_factory_.GetWeakPtr(),
480 kStorageTypeSyncable));
483 virtual void Completed() OVERRIDE {
484 callback_.Run(entries_);
488 virtual void Aborted() OVERRIDE {
489 callback_.Run(UsageInfoEntries());
494 void AddEntries(StorageType type, UsageTracker* tracker) {
495 std::map<std::string, int64> host_usage;
496 tracker->GetCachedHostsUsage(&host_usage);
497 for (std::map<std::string, int64>::const_iterator iter = host_usage.begin();
498 iter != host_usage.end();
500 entries_.push_back(UsageInfo(iter->first, type, iter->second));
502 if (--remaining_trackers_ == 0)
506 void DidGetGlobalUsage(StorageType type, int64, int64) {
507 DCHECK(manager()->GetUsageTracker(type));
508 AddEntries(type, manager()->GetUsageTracker(type));
511 QuotaManager* manager() const {
512 return static_cast<QuotaManager*>(observer());
515 GetUsageInfoCallback callback_;
516 UsageInfoEntries entries_;
517 int remaining_trackers_;
518 base::WeakPtrFactory<GetUsageInfoTask> weak_factory_;
520 DISALLOW_COPY_AND_ASSIGN(GetUsageInfoTask);
523 class QuotaManager::OriginDataDeleter : public QuotaTask {
525 OriginDataDeleter(QuotaManager* manager,
528 int quota_client_mask,
529 const StatusCallback& callback)
530 : QuotaTask(manager),
533 quota_client_mask_(quota_client_mask),
535 remaining_clients_(-1),
538 weak_factory_(this) {}
541 virtual void Run() OVERRIDE {
543 remaining_clients_ = manager()->clients_.size();
544 for (QuotaClientList::iterator iter = manager()->clients_.begin();
545 iter != manager()->clients_.end(); ++iter) {
546 if (quota_client_mask_ & (*iter)->id()) {
547 (*iter)->DeleteOriginData(
549 base::Bind(&OriginDataDeleter::DidDeleteOriginData,
550 weak_factory_.GetWeakPtr()));
553 if (--remaining_clients_ == 0)
559 virtual void Completed() OVERRIDE {
560 if (error_count_ == 0) {
561 // Only remove the entire origin if we didn't skip any client types.
562 if (skipped_clients_ == 0)
563 manager()->DeleteOriginFromDatabase(origin_, type_);
564 callback_.Run(kQuotaStatusOk);
566 callback_.Run(kQuotaErrorInvalidModification);
571 virtual void Aborted() OVERRIDE {
572 callback_.Run(kQuotaErrorAbort);
576 void DidDeleteOriginData(QuotaStatusCode status) {
577 DCHECK_GT(remaining_clients_, 0);
579 if (status != kQuotaStatusOk)
582 if (--remaining_clients_ == 0)
586 QuotaManager* manager() const {
587 return static_cast<QuotaManager*>(observer());
592 int quota_client_mask_;
594 int remaining_clients_;
595 int skipped_clients_;
596 StatusCallback callback_;
598 base::WeakPtrFactory<OriginDataDeleter> weak_factory_;
599 DISALLOW_COPY_AND_ASSIGN(OriginDataDeleter);
602 class QuotaManager::HostDataDeleter : public QuotaTask {
604 HostDataDeleter(QuotaManager* manager,
605 const std::string& host,
607 int quota_client_mask,
608 const StatusCallback& callback)
609 : QuotaTask(manager),
612 quota_client_mask_(quota_client_mask),
614 remaining_clients_(-1),
615 remaining_deleters_(-1),
617 weak_factory_(this) {}
620 virtual void Run() OVERRIDE {
622 remaining_clients_ = manager()->clients_.size();
623 for (QuotaClientList::iterator iter = manager()->clients_.begin();
624 iter != manager()->clients_.end(); ++iter) {
625 (*iter)->GetOriginsForHost(
627 base::Bind(&HostDataDeleter::DidGetOriginsForHost,
628 weak_factory_.GetWeakPtr()));
632 virtual void Completed() OVERRIDE {
633 if (error_count_ == 0) {
634 callback_.Run(kQuotaStatusOk);
636 callback_.Run(kQuotaErrorInvalidModification);
641 virtual void Aborted() OVERRIDE {
642 callback_.Run(kQuotaErrorAbort);
646 void DidGetOriginsForHost(const std::set<GURL>& origins) {
647 DCHECK_GT(remaining_clients_, 0);
649 origins_.insert(origins.begin(), origins.end());
651 if (--remaining_clients_ == 0) {
652 if (!origins_.empty())
653 ScheduleOriginsDeletion();
659 void ScheduleOriginsDeletion() {
660 remaining_deleters_ = origins_.size();
661 for (std::set<GURL>::const_iterator p = origins_.begin();
664 OriginDataDeleter* deleter =
665 new OriginDataDeleter(
666 manager(), *p, type_, quota_client_mask_,
667 base::Bind(&HostDataDeleter::DidDeleteOriginData,
668 weak_factory_.GetWeakPtr()));
673 void DidDeleteOriginData(QuotaStatusCode status) {
674 DCHECK_GT(remaining_deleters_, 0);
676 if (status != kQuotaStatusOk)
679 if (--remaining_deleters_ == 0)
683 QuotaManager* manager() const {
684 return static_cast<QuotaManager*>(observer());
689 int quota_client_mask_;
690 std::set<GURL> origins_;
692 int remaining_clients_;
693 int remaining_deleters_;
694 StatusCallback callback_;
696 base::WeakPtrFactory<HostDataDeleter> weak_factory_;
697 DISALLOW_COPY_AND_ASSIGN(HostDataDeleter);
700 class QuotaManager::GetModifiedSinceHelper {
702 bool GetModifiedSinceOnDBThread(StorageType type,
703 base::Time modified_since,
704 QuotaDatabase* database) {
706 return database->GetOriginsModifiedSince(type, &origins_, modified_since);
709 void DidGetModifiedSince(const base::WeakPtr<QuotaManager>& manager,
710 const GetOriginsCallback& callback,
714 // The operation was aborted.
715 callback.Run(std::set<GURL>(), type);
718 manager->DidDatabaseWork(success);
719 callback.Run(origins_, type);
723 std::set<GURL> origins_;
726 class QuotaManager::DumpQuotaTableHelper {
728 bool DumpQuotaTableOnDBThread(QuotaDatabase* database) {
730 return database->DumpQuotaTable(
731 new TableCallback(base::Bind(&DumpQuotaTableHelper::AppendEntry,
732 base::Unretained(this))));
735 void DidDumpQuotaTable(const base::WeakPtr<QuotaManager>& manager,
736 const DumpQuotaTableCallback& callback,
739 // The operation was aborted.
740 callback.Run(QuotaTableEntries());
743 manager->DidDatabaseWork(success);
744 callback.Run(entries_);
748 typedef QuotaDatabase::QuotaTableCallback TableCallback;
750 bool AppendEntry(const QuotaTableEntry& entry) {
751 entries_.push_back(entry);
755 QuotaTableEntries entries_;
758 class QuotaManager::DumpOriginInfoTableHelper {
760 bool DumpOriginInfoTableOnDBThread(QuotaDatabase* database) {
762 return database->DumpOriginInfoTable(
763 new TableCallback(base::Bind(&DumpOriginInfoTableHelper::AppendEntry,
764 base::Unretained(this))));
767 void DidDumpOriginInfoTable(const base::WeakPtr<QuotaManager>& manager,
768 const DumpOriginInfoTableCallback& callback,
771 // The operation was aborted.
772 callback.Run(OriginInfoTableEntries());
775 manager->DidDatabaseWork(success);
776 callback.Run(entries_);
780 typedef QuotaDatabase::OriginInfoTableCallback TableCallback;
782 bool AppendEntry(const OriginInfoTableEntry& entry) {
783 entries_.push_back(entry);
787 OriginInfoTableEntries entries_;
790 // QuotaManager ---------------------------------------------------------------
792 QuotaManager::QuotaManager(bool is_incognito,
793 const base::FilePath& profile_path,
794 base::SingleThreadTaskRunner* io_thread,
795 base::SequencedTaskRunner* db_thread,
796 SpecialStoragePolicy* special_storage_policy)
797 : is_incognito_(is_incognito),
798 profile_path_(profile_path),
799 proxy_(new QuotaManagerProxy(
802 eviction_disabled_(false),
803 io_thread_(io_thread),
804 db_thread_(db_thread),
805 temporary_quota_initialized_(false),
806 temporary_quota_override_(-1),
807 desired_available_space_(-1),
808 special_storage_policy_(special_storage_policy),
809 get_disk_space_fn_(&CallSystemGetAmountOfFreeDiskSpace),
810 weak_factory_(this) {
813 void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) {
815 GetUsageInfoTask* get_usage_info = new GetUsageInfoTask(this, callback);
816 get_usage_info->Start();
819 void QuotaManager::GetUsageAndQuotaForWebApps(
822 const GetUsageAndQuotaCallback& callback) {
823 if (type != kStorageTypeTemporary &&
824 type != kStorageTypePersistent &&
825 type != kStorageTypeSyncable) {
826 callback.Run(kQuotaErrorNotSupported, 0, 0);
830 DCHECK(origin == origin.GetOrigin());
833 bool unlimited = IsStorageUnlimited(origin, type);
834 bool can_query_disk_size = CanQueryDiskSize(origin);
836 UsageAndQuotaCallbackDispatcher* dispatcher =
837 new UsageAndQuotaCallbackDispatcher(this);
839 UsageAndQuota usage_and_quota;
841 dispatcher->set_quota(kNoLimit);
843 if (type == kStorageTypeTemporary) {
844 GetUsageTracker(type)->GetGlobalLimitedUsage(
845 dispatcher->GetGlobalLimitedUsageCallback());
846 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
847 } else if (type == kStorageTypePersistent) {
848 GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin),
849 dispatcher->GetQuotaCallback());
851 dispatcher->set_quota(kSyncableStorageDefaultHostQuota);
855 DCHECK(GetUsageTracker(type));
856 GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin),
857 dispatcher->GetHostUsageCallback());
859 if (!is_incognito_ && (unlimited || can_query_disk_size))
860 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
862 dispatcher->WaitForResults(base::Bind(
863 &DispatchUsageAndQuotaForWebApps,
864 type, is_incognito_, unlimited, can_query_disk_size,
868 void QuotaManager::GetUsageAndQuota(
869 const GURL& origin, StorageType type,
870 const GetUsageAndQuotaCallback& callback) {
871 DCHECK(origin == origin.GetOrigin());
873 if (IsStorageUnlimited(origin, type)) {
874 callback.Run(kQuotaStatusOk, 0, kNoLimit);
878 GetUsageAndQuotaForWebApps(origin, type, callback);
881 void QuotaManager::NotifyStorageAccessed(
882 QuotaClient::ID client_id,
883 const GURL& origin, StorageType type) {
884 DCHECK(origin == origin.GetOrigin());
885 NotifyStorageAccessedInternal(client_id, origin, type, base::Time::Now());
888 void QuotaManager::NotifyStorageModified(
889 QuotaClient::ID client_id,
890 const GURL& origin, StorageType type, int64 delta) {
891 DCHECK(origin == origin.GetOrigin());
892 NotifyStorageModifiedInternal(client_id, origin, type, delta,
896 void QuotaManager::NotifyOriginInUse(const GURL& origin) {
897 DCHECK(io_thread_->BelongsToCurrentThread());
898 origins_in_use_[origin]++;
901 void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) {
902 DCHECK(io_thread_->BelongsToCurrentThread());
903 DCHECK(IsOriginInUse(origin));
904 int& count = origins_in_use_[origin];
906 origins_in_use_.erase(origin);
909 void QuotaManager::SetUsageCacheEnabled(QuotaClient::ID client_id,
914 DCHECK(GetUsageTracker(type));
915 GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled);
918 void QuotaManager::DeleteOriginData(
919 const GURL& origin, StorageType type, int quota_client_mask,
920 const StatusCallback& callback) {
923 if (origin.is_empty() || clients_.empty()) {
924 callback.Run(kQuotaStatusOk);
928 DCHECK(origin == origin.GetOrigin());
929 OriginDataDeleter* deleter =
930 new OriginDataDeleter(this, origin, type, quota_client_mask, callback);
934 void QuotaManager::DeleteHostData(const std::string& host,
936 int quota_client_mask,
937 const StatusCallback& callback) {
940 if (host.empty() || clients_.empty()) {
941 callback.Run(kQuotaStatusOk);
945 HostDataDeleter* deleter =
946 new HostDataDeleter(this, host, type, quota_client_mask, callback);
950 void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) {
951 if (!available_space_callbacks_.Add(callback))
954 PostTaskAndReplyWithResult(db_thread_.get(),
956 base::Bind(get_disk_space_fn_, profile_path_),
957 base::Bind(&QuotaManager::DidGetAvailableSpace,
958 weak_factory_.GetWeakPtr()));
961 void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) {
963 if (!temporary_quota_initialized_) {
964 db_initialization_callbacks_.Add(base::Bind(
965 &QuotaManager::GetTemporaryGlobalQuota,
966 weak_factory_.GetWeakPtr(), callback));
970 if (temporary_quota_override_ > 0) {
971 callback.Run(kQuotaStatusOk, temporary_quota_override_);
975 UsageAndQuotaCallbackDispatcher* dispatcher =
976 new UsageAndQuotaCallbackDispatcher(this);
977 GetUsageTracker(kStorageTypeTemporary)->
978 GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
979 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
980 dispatcher->WaitForResults(
981 base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback));
984 void QuotaManager::SetTemporaryGlobalOverrideQuota(
985 int64 new_quota, const QuotaCallback& callback) {
989 if (!callback.is_null())
990 callback.Run(kQuotaErrorInvalidModification, -1);
995 if (callback.is_null())
996 callback.Run(kQuotaErrorInvalidAccess, -1);
1000 int64* new_quota_ptr = new int64(new_quota);
1001 PostTaskAndReplyWithResultForDBThread(
1003 base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread,
1004 base::Unretained(new_quota_ptr)),
1005 base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota,
1006 weak_factory_.GetWeakPtr(),
1008 base::Owned(new_quota_ptr)));
1011 void QuotaManager::GetPersistentHostQuota(const std::string& host,
1012 const QuotaCallback& callback) {
1015 // This could happen if we are called on file:///.
1016 // TODO(kinuko) We may want to respect --allow-file-access-from-files
1017 // command line switch.
1018 callback.Run(kQuotaStatusOk, 0);
1022 if (!persistent_host_quota_callbacks_.Add(host, callback))
1025 int64* quota_ptr = new int64(0);
1026 PostTaskAndReplyWithResultForDBThread(
1028 base::Bind(&GetPersistentHostQuotaOnDBThread,
1030 base::Unretained(quota_ptr)),
1031 base::Bind(&QuotaManager::DidGetPersistentHostQuota,
1032 weak_factory_.GetWeakPtr(),
1034 base::Owned(quota_ptr)));
1037 void QuotaManager::SetPersistentHostQuota(const std::string& host,
1039 const QuotaCallback& callback) {
1042 // This could happen if we are called on file:///.
1043 callback.Run(kQuotaErrorNotSupported, 0);
1046 if (new_quota < 0) {
1047 callback.Run(kQuotaErrorInvalidModification, -1);
1052 callback.Run(kQuotaErrorInvalidAccess, -1);
1056 int64* new_quota_ptr = new int64(new_quota);
1057 PostTaskAndReplyWithResultForDBThread(
1059 base::Bind(&SetPersistentHostQuotaOnDBThread,
1061 base::Unretained(new_quota_ptr)),
1062 base::Bind(&QuotaManager::DidSetPersistentHostQuota,
1063 weak_factory_.GetWeakPtr(),
1066 base::Owned(new_quota_ptr)));
1069 void QuotaManager::GetGlobalUsage(StorageType type,
1070 const GlobalUsageCallback& callback) {
1072 DCHECK(GetUsageTracker(type));
1073 GetUsageTracker(type)->GetGlobalUsage(callback);
1076 void QuotaManager::GetHostUsage(const std::string& host,
1078 const UsageCallback& callback) {
1080 DCHECK(GetUsageTracker(type));
1081 GetUsageTracker(type)->GetHostUsage(host, callback);
1084 void QuotaManager::GetHostUsage(const std::string& host,
1086 QuotaClient::ID client_id,
1087 const UsageCallback& callback) {
1089 DCHECK(GetUsageTracker(type));
1090 ClientUsageTracker* tracker =
1091 GetUsageTracker(type)->GetClientTracker(client_id);
1096 tracker->GetHostUsage(host, callback);
1099 bool QuotaManager::IsTrackingHostUsage(StorageType type,
1100 QuotaClient::ID client_id) const {
1101 UsageTracker* tracker = GetUsageTracker(type);
1102 return tracker && tracker->GetClientTracker(client_id);
1105 void QuotaManager::GetStatistics(
1106 std::map<std::string, std::string>* statistics) {
1108 if (temporary_storage_evictor_) {
1109 std::map<std::string, int64> stats;
1110 temporary_storage_evictor_->GetStatistics(&stats);
1111 for (std::map<std::string, int64>::iterator p = stats.begin();
1114 (*statistics)[p->first] = base::Int64ToString(p->second);
1118 bool QuotaManager::IsStorageUnlimited(const GURL& origin,
1119 StorageType type) const {
1120 // For syncable storage we should always enforce quota (since the
1121 // quota must be capped by the server limit).
1122 if (type == kStorageTypeSyncable)
1124 if (type == kStorageTypeQuotaNotManaged)
1126 return special_storage_policy_.get() &&
1127 special_storage_policy_->IsStorageUnlimited(origin);
1130 void QuotaManager::GetOriginsModifiedSince(StorageType type,
1131 base::Time modified_since,
1132 const GetOriginsCallback& callback) {
1134 GetModifiedSinceHelper* helper = new GetModifiedSinceHelper;
1135 PostTaskAndReplyWithResultForDBThread(
1137 base::Bind(&GetModifiedSinceHelper::GetModifiedSinceOnDBThread,
1138 base::Unretained(helper),
1141 base::Bind(&GetModifiedSinceHelper::DidGetModifiedSince,
1142 base::Owned(helper),
1143 weak_factory_.GetWeakPtr(),
1148 bool QuotaManager::ResetUsageTracker(StorageType type) {
1149 DCHECK(GetUsageTracker(type));
1150 if (GetUsageTracker(type)->IsWorking())
1153 case kStorageTypeTemporary:
1154 temporary_usage_tracker_.reset(new UsageTracker(
1155 clients_, kStorageTypeTemporary, special_storage_policy_.get()));
1157 case kStorageTypePersistent:
1158 persistent_usage_tracker_.reset(new UsageTracker(
1159 clients_, kStorageTypePersistent, special_storage_policy_.get()));
1161 case kStorageTypeSyncable:
1162 syncable_usage_tracker_.reset(new UsageTracker(
1163 clients_, kStorageTypeSyncable, special_storage_policy_.get()));
1171 QuotaManager::~QuotaManager() {
1172 proxy_->manager_ = NULL;
1173 std::for_each(clients_.begin(), clients_.end(),
1174 std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed));
1176 db_thread_->DeleteSoon(FROM_HERE, database_.release());
1179 QuotaManager::EvictionContext::EvictionContext()
1180 : evicted_type(kStorageTypeUnknown) {
1183 QuotaManager::EvictionContext::~EvictionContext() {
1186 void QuotaManager::LazyInitialize() {
1187 DCHECK(io_thread_->BelongsToCurrentThread());
1189 // Initialization seems to be done already.
1193 // Use an empty path to open an in-memory only databse for incognito.
1194 database_.reset(new QuotaDatabase(is_incognito_ ? base::FilePath() :
1195 profile_path_.AppendASCII(kDatabaseName)));
1197 temporary_usage_tracker_.reset(new UsageTracker(
1198 clients_, kStorageTypeTemporary, special_storage_policy_.get()));
1199 persistent_usage_tracker_.reset(new UsageTracker(
1200 clients_, kStorageTypePersistent, special_storage_policy_.get()));
1201 syncable_usage_tracker_.reset(new UsageTracker(
1202 clients_, kStorageTypeSyncable, special_storage_policy_.get()));
1204 int64* temporary_quota_override = new int64(-1);
1205 int64* desired_available_space = new int64(-1);
1206 PostTaskAndReplyWithResultForDBThread(
1208 base::Bind(&InitializeOnDBThread,
1209 base::Unretained(temporary_quota_override),
1210 base::Unretained(desired_available_space)),
1211 base::Bind(&QuotaManager::DidInitialize,
1212 weak_factory_.GetWeakPtr(),
1213 base::Owned(temporary_quota_override),
1214 base::Owned(desired_available_space)));
1217 void QuotaManager::RegisterClient(QuotaClient* client) {
1218 DCHECK(!database_.get());
1219 clients_.push_back(client);
1222 UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const {
1224 case kStorageTypeTemporary:
1225 return temporary_usage_tracker_.get();
1226 case kStorageTypePersistent:
1227 return persistent_usage_tracker_.get();
1228 case kStorageTypeSyncable:
1229 return syncable_usage_tracker_.get();
1230 case kStorageTypeQuotaNotManaged:
1232 case kStorageTypeUnknown:
1238 void QuotaManager::GetCachedOrigins(
1239 StorageType type, std::set<GURL>* origins) {
1242 DCHECK(GetUsageTracker(type));
1243 GetUsageTracker(type)->GetCachedOrigins(origins);
1246 void QuotaManager::NotifyStorageAccessedInternal(
1247 QuotaClient::ID client_id,
1248 const GURL& origin, StorageType type,
1249 base::Time accessed_time) {
1251 if (type == kStorageTypeTemporary && !lru_origin_callback_.is_null()) {
1252 // Record the accessed origins while GetLRUOrigin task is runing
1253 // to filter out them from eviction.
1254 access_notified_origins_.insert(origin);
1259 PostTaskAndReplyWithResultForDBThread(
1261 base::Bind(&UpdateAccessTimeOnDBThread, origin, type, accessed_time),
1262 base::Bind(&QuotaManager::DidDatabaseWork,
1263 weak_factory_.GetWeakPtr()));
1266 void QuotaManager::NotifyStorageModifiedInternal(
1267 QuotaClient::ID client_id,
1271 base::Time modified_time) {
1273 DCHECK(GetUsageTracker(type));
1274 GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
1276 PostTaskAndReplyWithResultForDBThread(
1278 base::Bind(&UpdateModifiedTimeOnDBThread, origin, type, modified_time),
1279 base::Bind(&QuotaManager::DidDatabaseWork,
1280 weak_factory_.GetWeakPtr()));
1283 void QuotaManager::DumpQuotaTable(const DumpQuotaTableCallback& callback) {
1284 DumpQuotaTableHelper* helper = new DumpQuotaTableHelper;
1285 PostTaskAndReplyWithResultForDBThread(
1287 base::Bind(&DumpQuotaTableHelper::DumpQuotaTableOnDBThread,
1288 base::Unretained(helper)),
1289 base::Bind(&DumpQuotaTableHelper::DidDumpQuotaTable,
1290 base::Owned(helper),
1291 weak_factory_.GetWeakPtr(),
1295 void QuotaManager::DumpOriginInfoTable(
1296 const DumpOriginInfoTableCallback& callback) {
1297 DumpOriginInfoTableHelper* helper = new DumpOriginInfoTableHelper;
1298 PostTaskAndReplyWithResultForDBThread(
1300 base::Bind(&DumpOriginInfoTableHelper::DumpOriginInfoTableOnDBThread,
1301 base::Unretained(helper)),
1302 base::Bind(&DumpOriginInfoTableHelper::DidDumpOriginInfoTable,
1303 base::Owned(helper),
1304 weak_factory_.GetWeakPtr(),
1308 void QuotaManager::StartEviction() {
1309 DCHECK(!temporary_storage_evictor_.get());
1310 temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(
1311 this, kEvictionIntervalInMilliSeconds));
1312 if (desired_available_space_ >= 0)
1313 temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction(
1314 desired_available_space_);
1315 temporary_storage_evictor_->Start();
1318 void QuotaManager::DeleteOriginFromDatabase(
1319 const GURL& origin, StorageType type) {
1324 PostTaskAndReplyWithResultForDBThread(
1326 base::Bind(&DeleteOriginInfoOnDBThread, origin, type),
1327 base::Bind(&QuotaManager::DidDatabaseWork,
1328 weak_factory_.GetWeakPtr()));
1331 void QuotaManager::DidOriginDataEvicted(QuotaStatusCode status) {
1332 DCHECK(io_thread_->BelongsToCurrentThread());
1334 // We only try evict origins that are not in use, so basically
1335 // deletion attempt for eviction should not fail. Let's record
1336 // the origin if we get error and exclude it from future eviction
1337 // if the error happens consistently (> kThresholdOfErrorsToBeBlacklisted).
1338 if (status != kQuotaStatusOk)
1339 origins_in_error_[eviction_context_.evicted_origin]++;
1341 eviction_context_.evict_origin_data_callback.Run(status);
1342 eviction_context_.evict_origin_data_callback.Reset();
1345 void QuotaManager::ReportHistogram() {
1346 GetGlobalUsage(kStorageTypeTemporary,
1348 &QuotaManager::DidGetTemporaryGlobalUsageForHistogram,
1349 weak_factory_.GetWeakPtr()));
1350 GetGlobalUsage(kStorageTypePersistent,
1352 &QuotaManager::DidGetPersistentGlobalUsageForHistogram,
1353 weak_factory_.GetWeakPtr()));
1356 void QuotaManager::DidGetTemporaryGlobalUsageForHistogram(
1358 int64 unlimited_usage) {
1359 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfTemporaryStorage", usage);
1361 std::set<GURL> origins;
1362 GetCachedOrigins(kStorageTypeTemporary, &origins);
1364 size_t num_origins = origins.size();
1365 size_t protected_origins = 0;
1366 size_t unlimited_origins = 0;
1367 CountOriginType(origins,
1368 special_storage_policy_.get(),
1370 &unlimited_origins);
1372 UMA_HISTOGRAM_COUNTS("Quota.NumberOfTemporaryStorageOrigins",
1374 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedTemporaryStorageOrigins",
1376 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedTemporaryStorageOrigins",
1380 void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
1382 int64 unlimited_usage) {
1383 UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage);
1385 std::set<GURL> origins;
1386 GetCachedOrigins(kStorageTypePersistent, &origins);
1388 size_t num_origins = origins.size();
1389 size_t protected_origins = 0;
1390 size_t unlimited_origins = 0;
1391 CountOriginType(origins,
1392 special_storage_policy_.get(),
1394 &unlimited_origins);
1396 UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
1398 UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
1400 UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
1404 void QuotaManager::GetLRUOrigin(
1406 const GetLRUOriginCallback& callback) {
1408 // This must not be called while there's an in-flight task.
1409 DCHECK(lru_origin_callback_.is_null());
1410 lru_origin_callback_ = callback;
1412 lru_origin_callback_.Run(GURL());
1413 lru_origin_callback_.Reset();
1417 std::set<GURL>* exceptions = new std::set<GURL>;
1418 for (std::map<GURL, int>::const_iterator p = origins_in_use_.begin();
1419 p != origins_in_use_.end();
1422 exceptions->insert(p->first);
1424 for (std::map<GURL, int>::const_iterator p = origins_in_error_.begin();
1425 p != origins_in_error_.end();
1427 if (p->second > QuotaManager::kThresholdOfErrorsToBeBlacklisted)
1428 exceptions->insert(p->first);
1431 GURL* url = new GURL;
1432 PostTaskAndReplyWithResultForDBThread(
1434 base::Bind(&GetLRUOriginOnDBThread,
1436 base::Owned(exceptions),
1437 special_storage_policy_,
1438 base::Unretained(url)),
1439 base::Bind(&QuotaManager::DidGetLRUOrigin,
1440 weak_factory_.GetWeakPtr(),
1444 void QuotaManager::EvictOriginData(
1447 const EvictOriginDataCallback& callback) {
1448 DCHECK(io_thread_->BelongsToCurrentThread());
1449 DCHECK_EQ(type, kStorageTypeTemporary);
1451 eviction_context_.evicted_origin = origin;
1452 eviction_context_.evicted_type = type;
1453 eviction_context_.evict_origin_data_callback = callback;
1455 DeleteOriginData(origin, type, QuotaClient::kAllClientsMask,
1456 base::Bind(&QuotaManager::DidOriginDataEvicted,
1457 weak_factory_.GetWeakPtr()));
1460 void QuotaManager::GetUsageAndQuotaForEviction(
1461 const UsageAndQuotaCallback& callback) {
1462 DCHECK(io_thread_->BelongsToCurrentThread());
1465 UsageAndQuotaCallbackDispatcher* dispatcher =
1466 new UsageAndQuotaCallbackDispatcher(this);
1467 GetUsageTracker(kStorageTypeTemporary)->
1468 GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback());
1469 GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback());
1470 GetAvailableSpace(dispatcher->GetAvailableSpaceCallback());
1471 dispatcher->WaitForResults(callback);
1474 void QuotaManager::DidSetTemporaryGlobalOverrideQuota(
1475 const QuotaCallback& callback,
1476 const int64* new_quota,
1478 QuotaStatusCode status = kQuotaErrorInvalidAccess;
1479 DidDatabaseWork(success);
1481 temporary_quota_override_ = *new_quota;
1482 status = kQuotaStatusOk;
1485 if (callback.is_null())
1488 callback.Run(status, *new_quota);
1491 void QuotaManager::DidGetPersistentHostQuota(const std::string& host,
1494 DidDatabaseWork(success);
1495 persistent_host_quota_callbacks_.Run(
1496 host, MakeTuple(kQuotaStatusOk, *quota));
1499 void QuotaManager::DidSetPersistentHostQuota(const std::string& host,
1500 const QuotaCallback& callback,
1501 const int64* new_quota,
1503 DidDatabaseWork(success);
1504 callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota);
1507 void QuotaManager::DidInitialize(int64* temporary_quota_override,
1508 int64* desired_available_space,
1510 temporary_quota_override_ = *temporary_quota_override;
1511 desired_available_space_ = *desired_available_space;
1512 temporary_quota_initialized_ = true;
1513 DidDatabaseWork(success);
1515 histogram_timer_.Start(FROM_HERE,
1516 base::TimeDelta::FromMilliseconds(
1517 kReportHistogramInterval),
1518 this, &QuotaManager::ReportHistogram);
1520 db_initialization_callbacks_.Run(MakeTuple());
1521 GetTemporaryGlobalQuota(
1522 base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota,
1523 weak_factory_.GetWeakPtr()));
1526 void QuotaManager::DidGetLRUOrigin(const GURL* origin,
1528 DidDatabaseWork(success);
1529 // Make sure the returned origin is (still) not in the origin_in_use_ set
1530 // and has not been accessed since we posted the task.
1531 if (origins_in_use_.find(*origin) != origins_in_use_.end() ||
1532 access_notified_origins_.find(*origin) != access_notified_origins_.end())
1533 lru_origin_callback_.Run(GURL());
1535 lru_origin_callback_.Run(*origin);
1536 access_notified_origins_.clear();
1537 lru_origin_callback_.Reset();
1540 void QuotaManager::DidGetInitialTemporaryGlobalQuota(
1541 QuotaStatusCode status, int64 quota_unused) {
1542 if (eviction_disabled_)
1545 std::set<GURL>* origins = new std::set<GURL>;
1546 temporary_usage_tracker_->GetCachedOrigins(origins);
1547 // This will call the StartEviction() when initial origin registration
1549 PostTaskAndReplyWithResultForDBThread(
1551 base::Bind(&InitializeTemporaryOriginsInfoOnDBThread,
1552 base::Owned(origins)),
1553 base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo,
1554 weak_factory_.GetWeakPtr()));
1557 void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) {
1558 DidDatabaseWork(success);
1563 void QuotaManager::DidGetAvailableSpace(int64 space) {
1564 available_space_callbacks_.Run(MakeTuple(kQuotaStatusOk, space));
1567 void QuotaManager::DidDatabaseWork(bool success) {
1568 db_disabled_ = !success;
1571 void QuotaManager::DeleteOnCorrectThread() const {
1572 if (!io_thread_->BelongsToCurrentThread() &&
1573 io_thread_->DeleteSoon(FROM_HERE, this)) {
1579 void QuotaManager::PostTaskAndReplyWithResultForDBThread(
1580 const tracked_objects::Location& from_here,
1581 const base::Callback<bool(QuotaDatabase*)>& task,
1582 const base::Callback<void(bool)>& reply) {
1583 // Deleting manager will post another task to DB thread to delete
1584 // |database_|, therefore we can be sure that database_ is alive when this
1586 base::PostTaskAndReplyWithResult(
1589 base::Bind(task, base::Unretained(database_.get())),
1593 // QuotaManagerProxy ----------------------------------------------------------
1595 void QuotaManagerProxy::RegisterClient(QuotaClient* client) {
1596 if (!io_thread_->BelongsToCurrentThread() &&
1597 io_thread_->PostTask(
1599 base::Bind(&QuotaManagerProxy::RegisterClient, this, client))) {
1604 manager_->RegisterClient(client);
1606 client->OnQuotaManagerDestroyed();
1609 void QuotaManagerProxy::NotifyStorageAccessed(
1610 QuotaClient::ID client_id,
1613 if (!io_thread_->BelongsToCurrentThread()) {
1614 io_thread_->PostTask(
1616 base::Bind(&QuotaManagerProxy::NotifyStorageAccessed, this, client_id,
1622 manager_->NotifyStorageAccessed(client_id, origin, type);
1625 void QuotaManagerProxy::NotifyStorageModified(
1626 QuotaClient::ID client_id,
1630 if (!io_thread_->BelongsToCurrentThread()) {
1631 io_thread_->PostTask(
1633 base::Bind(&QuotaManagerProxy::NotifyStorageModified, this, client_id,
1634 origin, type, delta));
1639 manager_->NotifyStorageModified(client_id, origin, type, delta);
1642 void QuotaManagerProxy::NotifyOriginInUse(
1643 const GURL& origin) {
1644 if (!io_thread_->BelongsToCurrentThread()) {
1645 io_thread_->PostTask(
1647 base::Bind(&QuotaManagerProxy::NotifyOriginInUse, this, origin));
1652 manager_->NotifyOriginInUse(origin);
1655 void QuotaManagerProxy::NotifyOriginNoLongerInUse(
1656 const GURL& origin) {
1657 if (!io_thread_->BelongsToCurrentThread()) {
1658 io_thread_->PostTask(
1660 base::Bind(&QuotaManagerProxy::NotifyOriginNoLongerInUse, this,
1665 manager_->NotifyOriginNoLongerInUse(origin);
1668 void QuotaManagerProxy::SetUsageCacheEnabled(QuotaClient::ID client_id,
1672 if (!io_thread_->BelongsToCurrentThread()) {
1673 io_thread_->PostTask(
1675 base::Bind(&QuotaManagerProxy::SetUsageCacheEnabled, this,
1676 client_id, origin, type, enabled));
1680 manager_->SetUsageCacheEnabled(client_id, origin, type, enabled);
1683 QuotaManager* QuotaManagerProxy::quota_manager() const {
1684 DCHECK(!io_thread_.get() || io_thread_->BelongsToCurrentThread());
1688 QuotaManagerProxy::QuotaManagerProxy(
1689 QuotaManager* manager, base::SingleThreadTaskRunner* io_thread)
1690 : manager_(manager), io_thread_(io_thread) {
1693 QuotaManagerProxy::~QuotaManagerProxy() {
1696 } // namespace quota