blob: 8f1d28e6e0473636fe00572f7ea3fb8dae116c88 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_IMPL_H_
#define STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_IMPL_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation_traits.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/services/storage/public/cpp/buckets/bucket_info.h"
#include "components/services/storage/public/cpp/buckets/bucket_init_params.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/cpp/quota_error_or.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "storage/browser/quota/quota_availability.h"
#include "storage/browser/quota/quota_callbacks.h"
#include "storage/browser/quota/quota_client_type.h"
#include "storage/browser/quota/quota_database.h"
#include "storage/browser/quota/quota_internals.mojom.h"
#include "storage/browser/quota/quota_manager_observer.mojom.h"
#include "storage/browser/quota/quota_settings.h"
#include "storage/browser/quota/quota_task.h"
#include "storage/browser/quota/special_storage_policy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-forward.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h"
namespace base {
class SequencedTaskRunner;
class SingleThreadTaskRunner;
class TaskRunner;
} // namespace base
namespace storage {
class QuotaManagerProxy;
class QuotaOverrideHandle;
class QuotaTemporaryStorageEvictor;
class UsageTracker;
// An interface called by QuotaTemporaryStorageEvictor. This is a grab bag of
// methods called by QuotaTemporaryStorageEvictor that need to be stubbed for
// testing.
class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaEvictionHandler {
public:
using EvictionRoundInfoCallback =
base::OnceCallback<void(blink::mojom::QuotaStatusCode status,
const QuotaSettings& settings,
int64_t available_space,
int64_t total_space,
int64_t global_usage,
bool global_usage_is_complete)>;
// Deletes all buckets that have explicit expiration dates which have passed.
virtual void EvictExpiredBuckets(StatusCallback done) = 0;
// Called at the beginning of an eviction round to gather the info about
// the current settings, capacity, and usage.
virtual void GetEvictionRoundInfo(EvictionRoundInfoCallback callback) = 0;
// Returns the next bucket to evict, or nullopt if there are no evictable
// buckets.
virtual void GetEvictionBuckets(int64_t target_usage,
GetBucketsCallback callback) = 0;
// Called to evict a set of buckets. The callback will be run with the number
// of successfully evicted buckets.
virtual void EvictBucketData(const std::set<BucketLocator>& buckets,
base::OnceCallback<void(int)> callback) = 0;
protected:
virtual ~QuotaEvictionHandler() = default;
};
struct UsageInfo {
UsageInfo(std::string host, blink::mojom::StorageType type, int64_t usage)
: host(std::move(host)), type(type), usage(usage) {}
const std::string host;
const blink::mojom::StorageType type;
const int64_t usage;
bool operator==(const UsageInfo& that) const {
return std::tie(host, usage, type) ==
std::tie(that.host, that.usage, that.type);
}
friend std::ostream& operator<<(std::ostream& os,
const UsageInfo& usage_info) {
return os << "{\"" << usage_info.host << "\", " << usage_info.type << ", "
<< usage_info.usage << "}";
}
};
struct AccumulateQuotaInternalsInfo {
int64_t total_space = 0;
int64_t available_space = 0;
int64_t temp_pool_size = 0;
};
// Entry point into the Quota System
//
// Each StoragePartition has exactly one QuotaManagerImpl instance, which
// coordinates quota across the Web platform features subject to quota.
// Each storage system interacts with quota via their own implementations of
// the QuotaClient interface.
//
// The class sets limits and defines the parameters of the systems heuristics.
// QuotaManagerImpl coordinates clients to orchestrate the collection of usage
// information, enforce quota limits, and evict stale data.
//
// The constructor and proxy() methods can be called on any thread. All other
// methods must be called on the IO thread.
class COMPONENT_EXPORT(STORAGE_BROWSER) QuotaManagerImpl
: public QuotaTaskObserver,
public QuotaEvictionHandler,
public base::RefCountedDeleteOnSequence<QuotaManagerImpl>,
public storage::mojom::QuotaInternalsHandler {
public:
using UsageAndQuotaCallback = base::OnceCallback<
void(blink::mojom::QuotaStatusCode, int64_t usage, int64_t quota)>;
using UsageAndQuotaWithBreakdownCallback =
base::OnceCallback<void(blink::mojom::QuotaStatusCode,
int64_t usage,
int64_t quota,
blink::mojom::UsageBreakdownPtr usage_breakdown)>;
using UsageAndQuotaForDevtoolsCallback =
base::OnceCallback<void(blink::mojom::QuotaStatusCode,
int64_t usage,
int64_t quota,
bool is_override_enabled,
blink::mojom::UsageBreakdownPtr usage_breakdown)>;
// Function pointer type used to store the function which returns
// information about the volume containing the given FilePath.
// The value returned is the QuotaAvailability struct.
using GetVolumeInfoFn = QuotaAvailability (*)(const base::FilePath&);
static constexpr int64_t kGBytes = 1024 * 1024 * 1024;
static constexpr int64_t kNoLimit = INT64_MAX;
static constexpr int64_t kMBytes = 1024 * 1024;
// A "typical" amount of usage expected for a bucket. This is used to
// dynamically limit the number of buckets that may be created: the quota for
// a site divided by this number is an upper bound for the number of buckets
// it's allowed.
static constexpr int64_t kTypicalBucketUsage = 20 * kMBytes;
static constexpr int kMinutesInMilliSeconds = 60 * 1000;
QuotaManagerImpl(bool is_incognito,
const base::FilePath& profile_path,
scoped_refptr<base::SingleThreadTaskRunner> io_thread,
base::RepeatingClosure quota_change_callback,
scoped_refptr<SpecialStoragePolicy> special_storage_policy,
const GetQuotaSettingsFunc& get_settings_function);
QuotaManagerImpl(const QuotaManagerImpl&) = delete;
QuotaManagerImpl& operator=(const QuotaManagerImpl&) = delete;
const QuotaSettings& settings() const { return settings_; }
void SetQuotaSettings(const QuotaSettings& settings);
// Returns a proxy object that can be used on any thread.
QuotaManagerProxy* proxy() { return proxy_.get(); }
void BindInternalsHandler(
mojo::PendingReceiver<mojom::QuotaInternalsHandler> receiver);
// Gets the bucket with `bucket_name` for the `storage_key` for
// StorageType kTemporary and returns the BucketInfo. This may update
// expiration and persistence if the existing attributes don't match those
// found in `bucket_params`, and may clobber the bucket and rebuild it if it's
// expired. If a bucket doesn't exist, a new bucket is created with the
// specified policies. If the existing bucket exists but has expired, it will
// be clobbered and recreated. Returns a QuotaError if the operation has
// failed. This method is declared as virtual to allow test code to override
// it.
virtual void UpdateOrCreateBucket(
const BucketInitParams& bucket_params,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)>);
// Same as UpdateOrCreateBucket but takes in StorageType. This should only be
// used by FileSystem, and is expected to be removed when
// StorageType::kSyncable and StorageType::kPersistent are deprecated.
// (crbug.com/1233525, crbug.com/1286964).
virtual void GetOrCreateBucketDeprecated(
const BucketInitParams& bucket_params,
blink::mojom::StorageType storage_type,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)>);
// Creates a bucket for `origin` with `bucket_name` and returns BucketInfo
// to the callback. Will return a QuotaError to the callback on operation
// failure.
//
// TODO(crbug.com/1208141): Remove `storage_type` when the only supported
// StorageType is kTemporary.
virtual void CreateBucketForTesting(
const blink::StorageKey& storage_key,
const std::string& bucket_name,
blink::mojom::StorageType storage_type,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)>);
// Retrieves the BucketInfo of the bucket with `bucket_name` for `storage_key`
// and returns it to the callback. Will return a QuotaError if the bucket does
// not exist or on operation failure.
// This SHOULD NOT be used once you have the ID for a bucket. Prefer
// GetBucketById.
virtual void GetBucketByNameUnsafe(
const blink::StorageKey& storage_key,
const std::string& bucket_name,
blink::mojom::StorageType type,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)>);
// Retrieves the BucketInfo of the bucket with `bucket_id` and returns it to
// the callback. Will return a QuotaError if the bucket does not exist or on
// operation failure. This method is declared as virtual to allow test code
// to override it.
virtual void GetBucketById(
const BucketId& bucket_id,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)>);
// Retrieves all storage keys for `type` that are in the buckets table.
// Used for listing storage keys when showing storage key quota usage.
void GetStorageKeysForType(blink::mojom::StorageType type,
GetStorageKeysCallback callback);
// Retrieves all buckets for `type` that are in the buckets table.
// Used for retrieving global usage data in the UsageTracker.
void GetBucketsForType(
blink::mojom::StorageType type,
base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback);
// Retrieves all buckets for `host` and `type` that are in the buckets table.
// Used for retrieving host usage data in the UsageTracker.
void GetBucketsForHost(
const std::string& host,
blink::mojom::StorageType type,
base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback);
// Retrieves all buckets for `storage_key` and `type` that are in the buckets
// table. When `delete_expired` is true, the expired buckets will be filtered
// out of the reply and also deleted from disk.
virtual void GetBucketsForStorageKey(
const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
bool delete_expired = false);
// Called by clients or webapps. Returns usage per host.
void GetUsageInfo(GetUsageInfoCallback callback);
// Called by Web Apps (deprecated quota API).
// This method is declared as virtual to allow test code to override it.
void GetUsageAndQuotaForWebApps(const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
UsageAndQuotaCallback callback);
// Called by Web Apps (navigator.storage.estimate())
// This method is declared as virtual to allow test code to override it.
virtual void GetUsageAndQuotaWithBreakdown(
const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
UsageAndQuotaWithBreakdownCallback callback);
// Called by DevTools.
virtual void GetUsageAndQuotaForDevtools(
const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
UsageAndQuotaForDevtoolsCallback callback);
// Called by storage backends.
//
// For UnlimitedStorage storage keys, this version skips usage and quota
// handling to avoid extra query cost. Do not call this method for
// apps/user-facing code.
//
// This method is declared as virtual to allow test code to override it.
virtual void GetUsageAndQuota(const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
UsageAndQuotaCallback callback);
// Called by storage backends via proxy.
//
// Quota-managed storage backends should call this method when a bucket is
// accessed. Used to maintain LRU ordering.
void NotifyBucketAccessed(const BucketLocator& bucket,
base::Time access_time);
// Called by storage backends via proxy.
//
// Quota-managed storage backends must call this method when they have made
// any modifications that change the amount of data stored in a bucket.
void NotifyBucketModified(QuotaClientType client_id,
const BucketLocator& bucket,
int64_t delta,
base::Time modification_time,
base::OnceClosure callback);
// Client storage must call this method whenever they run into disk
// write errors. Used as a hint to determine if the storage partition is out
// of space, and trigger actions if deemed appropriate.
//
// This method is declared as virtual to allow test code to override it.
virtual void OnClientWriteFailed(const blink::StorageKey& storage_key);
void SetUsageCacheEnabled(QuotaClientType client_id,
const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
bool enabled);
// Deletes `bucket` data for the specified `quota_client_types`. Pass in
// QuotaClientType::AllClients() to remove bucket data for all quota clients.
//
// `callback` is always called. If this QuotaManager gets destroyed during
// deletion, `callback` may be called with a kErrorAbort status.
virtual void DeleteBucketData(const BucketLocator& bucket,
QuotaClientTypes quota_client_types,
StatusCallback callback);
// Deletes buckets of a particular blink::mojom::StorageType with storage keys
// that match the specified host.
//
// `callback` is always called. If this QuotaManager gets destroyed during
// deletion, `callback` may be called with a kErrorAbort status.
// TODO(estade): Consider removing the status code from `callback` as it's
// unused outside of tests.
void DeleteHostData(const std::string& host,
blink::mojom::StorageType type,
StatusCallback callback);
// Queries QuotaDatabase for the bucket with `storage_key` and `bucket_name`
// for StorageType::kTemporary and deletes bucket data for all clients for the
// bucket. Used by the Storage Bucket API for bucket deletion. If no bucket is
// found, it will return QuotaStatusCode::kOk since it has no bucket data to
// delete.
virtual void FindAndDeleteBucketData(const blink::StorageKey& storage_key,
const std::string& bucket_name,
StatusCallback callback);
// Updates the expiration for the given bucket.
void UpdateBucketExpiration(
BucketId bucket,
const base::Time& expiration,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback);
// Updates the persistence bit for the given bucket.
virtual void UpdateBucketPersistence(
BucketId bucket,
bool persistent,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback);
// Instructs each QuotaClient to remove possible traces of deleted
// data on the disk.
void PerformStorageCleanup(blink::mojom::StorageType type,
QuotaClientTypes quota_client_types,
base::OnceClosure callback);
// storage::mojom::QuotaInternalsHandler implementation
void GetDiskAvailabilityAndTempPoolSize(
GetDiskAvailabilityAndTempPoolSizeCallback callback) override;
void GetStatistics(GetStatisticsCallback callback) override;
void RetrieveBucketsTable(RetrieveBucketsTableCallback callback) override;
void GetGlobalUsageForInternals(
blink::mojom::StorageType storage_type,
GetGlobalUsageForInternalsCallback callback) override;
// Used from quota-internals page to test behavior of the storage pressure
// callback.
void SimulateStoragePressure(const url::Origin& origin_url) override;
void IsSimulateStoragePressureAvailable(
IsSimulateStoragePressureAvailableCallback callback) override;
// QuotaEvictionHandler.
void EvictExpiredBuckets(StatusCallback done) override;
void GetEvictionBuckets(int64_t target_usage,
GetBucketsCallback callback) override;
void EvictBucketData(const std::set<BucketLocator>& buckets,
base::OnceCallback<void(int)> callback) override;
void GetEvictionRoundInfo(EvictionRoundInfoCallback callback) override;
// Called by UI and internal modules.
void GetGlobalUsage(blink::mojom::StorageType type, UsageCallback callback);
void GetStorageKeyUsageWithBreakdown(const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
UsageWithBreakdownCallback callback);
void GetBucketUsageWithBreakdown(const BucketLocator& bucket,
UsageWithBreakdownCallback callback);
void GetBucketUsageAndQuota(BucketId id, UsageAndQuotaCallback callback);
void GetBucketSpaceRemaining(
const BucketLocator& bucket,
base::OnceCallback<void(QuotaErrorOr<int64_t>)> callback);
bool IsStorageUnlimited(const blink::StorageKey& storage_key,
blink::mojom::StorageType type) const;
// Calculates the quota for the given storage key, taking into account whether
// the storage should be session only for this key. This will return 0 for
// unlimited storage situations.
// Virtual for testing.
virtual int64_t GetQuotaForStorageKey(const blink::StorageKey& storage_key,
blink::mojom::StorageType type,
const QuotaSettings& settings) const;
virtual void GetBucketsModifiedBetween(blink::mojom::StorageType type,
base::Time begin,
base::Time end,
GetBucketsCallback callback);
bool ResetUsageTracker(blink::mojom::StorageType type);
// Called when StoragePartition is initialized if embedder has an
// implementation of StorageNotificationService.
void SetStoragePressureCallback(
base::RepeatingCallback<void(const blink::StorageKey&)>
storage_pressure_callback);
// DevTools Quota Override methods:
int GetOverrideHandleId();
void OverrideQuotaForStorageKey(int handle_id,
const blink::StorageKey& storage_key,
absl::optional<int64_t> quota_size);
// Called when a DevTools client releases all overrides, however, overrides
// will not be disabled for any storage keys for which there are other
// DevTools clients/QuotaOverrideHandle with an active override.
void WithdrawOverridesForHandle(int handle_id);
static constexpr int kEvictionIntervalInMilliSeconds =
30 * kMinutesInMilliSeconds;
static constexpr int kThresholdOfErrorsToBeDenylisted = 3;
static constexpr int kThresholdRandomizationPercent = 5;
static constexpr char kDatabaseName[] = "QuotaManager";
static constexpr char kEvictedBucketAccessedCountHistogram[] =
"Quota.EvictedBucketAccessCount";
static constexpr char kEvictedBucketDaysSinceAccessHistogram[] =
"Quota.EvictedBucketDaysSinceAccess";
// Kept non-const so that test code can change the value.
// TODO(kinuko): Make this a real const value and add a proper way to set
// the quota for syncable storage. (http://crbug.com/155488)
static int64_t kSyncableStorageDefaultStorageKeyQuota;
void SetGetVolumeInfoFnForTesting(GetVolumeInfoFn fn) {
get_volume_info_fn_ = fn;
}
void SetEvictionDisabledForTesting(bool disable) {
eviction_disabled_ = disable;
}
// Testing support for handling corruption in the underlying database.
//
// Runs `corrupter` on the same sequence used to do database I/O,
// guaranteeing that no other database operation is performed at the same
// time. `corrupter` receives the path to the underlying SQLite database as an
// argument. The underlying SQLite database is closed while `corrupter` runs,
// and reopened afterwards.
//
// `callback` is called with QuotaError::kNone if the database was
// successfully reopened after `corrupter` was run, or with
// QuotaError::kDatabaseError otherwise.
void CorruptDatabaseForTesting(
base::OnceCallback<void(const base::FilePath&)> corrupter,
base::OnceCallback<void(QuotaError)> callback);
void SetBootstrapDisabledForTesting(bool disable) {
bootstrap_disabled_for_testing_ = disable;
}
bool is_bootstrapping_database_for_testing() {
return is_bootstrapping_database_;
}
bool is_db_disabled_for_testing() { return db_disabled_; }
void AddObserver(
mojo::PendingRemote<storage::mojom::QuotaManagerObserver> observer);
protected:
~QuotaManagerImpl() override;
void SetQuotaChangeCallbackForTesting(
base::RepeatingClosure storage_pressure_event_callback);
private:
friend class base::DeleteHelper<QuotaManagerImpl>;
friend class base::RefCountedDeleteOnSequence<QuotaManagerImpl>;
friend class MockQuotaManager;
friend class MockQuotaClient;
friend class QuotaManagerProxy;
friend class QuotaManagerImplTest;
friend class QuotaTemporaryStorageEvictor;
friend class UsageTrackerTest;
FRIEND_TEST_ALL_PREFIXES(QuotaManagerImplTest,
UpdateOrCreateBucket_Expiration);
class EvictionRoundInfoHelper;
class UsageAndQuotaInfoGatherer;
class GetUsageInfoTask;
class StorageKeyGathererTask;
class BucketDataDeleter;
class BucketSetDataDeleter;
class DumpBucketTableHelper;
class StorageCleanupHelper;
struct QuotaOverride {
QuotaOverride();
~QuotaOverride();
QuotaOverride(const QuotaOverride& quota_override) = delete;
QuotaOverride& operator=(const QuotaOverride&) = delete;
int64_t quota_size;
// Keeps track of the DevTools clients that have an active override.
std::set<int> active_override_session_ids;
};
using BucketTableEntries = std::vector<mojom::BucketTableEntryPtr>;
using StorageKeysByType =
base::flat_map<blink::mojom::StorageType, std::set<blink::StorageKey>>;
using QuotaSettingsCallback = base::OnceCallback<void(const QuotaSettings&)>;
using DumpBucketTableCallback = base::OnceCallback<void(BucketTableEntries)>;
// The values returned total_space, available_space.
using StorageCapacityCallback = base::OnceCallback<void(int64_t, int64_t)>;
// Lazily called on the IO thread when the first quota manager API is called.
//
// Initialize() must be called after all quota clients are added to the
// manager by RegisterClient().
void EnsureDatabaseOpened();
// Bootstraps database with storage keys that may not have been registered.
// Bootstrapping ensures that there is a bucket entry in the buckets table for
// all storage keys that have stored data by quota managed Storage APIs. Will
// queue calls to QuotaDatabase during bootstrap to be run after bootstrapping
// is complete.
void BootstrapDatabase();
void DidGetBootstrapFlag(bool is_database_bootstrapped);
void DidGetStorageKeysForBootstrap(StorageKeysByType storage_keys_by_type);
void DidBootstrapDatabase(QuotaError error);
void DidSetDatabaseBootstrapped(QuotaError error);
// Runs all callbacks to QuotaDatabase that have been queued during bootstrap.
void RunDatabaseCallbacks();
// Called by clients via proxy.
// Registers a quota client to the manager.
void RegisterClient(
mojo::PendingRemote<mojom::QuotaClient> client,
QuotaClientType client_type,
const std::vector<blink::mojom::StorageType>& storage_types);
UsageTracker* GetUsageTracker(blink::mojom::StorageType type) const;
void DumpBucketTable(DumpBucketTableCallback callback);
void UpdateQuotaInternalsDiskAvailability(base::OnceClosure barrier_callback,
AccumulateQuotaInternalsInfo* info,
int64_t total_space,
int64_t available_space);
void UpdateQuotaInternalsTempPoolSpace(base::OnceClosure barrier_callback,
AccumulateQuotaInternalsInfo* info,
const QuotaSettings& settings);
void FinallySendDiskAvailabilityAndTempPoolSize(
GetDiskAvailabilityAndTempPoolSizeCallback callback,
std::unique_ptr<AccumulateQuotaInternalsInfo> info);
void RetrieveBucketUsageForBucketTable(RetrieveBucketsTableCallback callback,
BucketTableEntries entries);
void AddBucketTableEntry(
mojom::BucketTableEntryPtr entry,
base::OnceCallback<void(mojom::BucketTableEntryPtr)> barrier_callback,
int64_t usage,
blink::mojom::UsageBreakdownPtr bucket_usage_breakdown);
// Runs BucketDataDeleter which calls QuotaClients to clear data for the
// bucket. Once the task is complete, calls the QuotaDatabase to delete the
// bucket from the bucket table.
void DeleteBucketDataInternal(
const BucketLocator& bucket,
QuotaClientTypes quota_client_types,
base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
callback);
// Removes the BucketSetDataDeleter that completed its work.
//
// This method is static because it must call `callback` even if the
// QuotaManagerImpl was destroyed.
static void DidDeleteBuckets(base::WeakPtr<QuotaManagerImpl> quota_manager,
StatusCallback callback,
BucketSetDataDeleter* deleter,
blink::mojom::QuotaStatusCode status_code);
// Removes the BucketDataDeleter that completed its work.
//
// This method is static because it must call `delete_bucket_data_callback`
// even if the QuotaManagerImpl was destroyed.
static void DidDeleteBucketData(
base::WeakPtr<QuotaManagerImpl> quota_manager,
base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
callback,
BucketDataDeleter* deleter,
QuotaErrorOr<mojom::BucketTableEntryPtr> result);
// Called after bucket data has been deleted from clients as well as the
// database due to bucket expiration. This will recreate the bucket in the
// database and pass it to `callback`.
void DidDeleteBucketForRecreation(
const BucketInitParams& params,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
BucketInfo bucket_info,
QuotaErrorOr<mojom::BucketTableEntryPtr> result);
// Called when the quota database encounters an error.
void OnDbError(int error_code);
// Called when the quota database or a quota client run into low disk space
// errors.
void OnFullDiskError(absl::optional<blink::StorageKey> storage_key);
// Notifies the embedder that space is too low. This ends up showing a
// user-facing dialog in Chrome.
void NotifyWriteFailed(const blink::StorageKey& storage_key);
// Methods for eviction logic.
void StartEviction();
void DeleteBucketFromDatabase(
const BucketLocator& bucket,
bool commit_immediately,
base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
callback);
// `barrier` should be called with true for a successful eviction or false if
// there's an error.
void DidEvictBucketData(BucketId evicted_bucket_id,
base::RepeatingCallback<void(bool)> barrier,
QuotaErrorOr<mojom::BucketTableEntryPtr> entry);
void ReportHistogram();
void DidGetTemporaryGlobalUsageForHistogram(int64_t usage,
int64_t unlimited_usage);
void DidGetStorageCapacityForHistogram(int64_t usage,
int64_t total_space,
int64_t available_space);
void DidDumpBucketTableForHistogram(BucketTableEntries entries);
// Returns the list of bucket ids that should be excluded from eviction due to
// consistent errors after multiple attempts.
std::set<BucketId> GetEvictionBucketExceptions();
void DidGetEvictionBuckets(GetBucketsCallback callback,
const std::set<BucketLocator>& buckets);
void DidGetEvictionRoundInfo();
void GetBucketsForEvictionFromDatabase(
int64_t target_usage,
std::map<BucketLocator, int64_t> usage_map,
GetBucketsCallback callback);
void DidGetBucketsForEvictionFromDatabase(
GetBucketsCallback callback,
QuotaErrorOr<std::set<BucketLocator>> result);
void GetQuotaSettings(QuotaSettingsCallback callback);
void DidGetSettings(absl::optional<QuotaSettings> settings);
void GetStorageCapacity(StorageCapacityCallback callback);
void ContinueIncognitoGetStorageCapacity(const QuotaSettings& settings);
void DidGetStorageCapacity(const QuotaAvailability& total_and_available);
void DidRazeForReBootstrap(QuotaError raze_and_reopen_result);
void NotifyUpdatedBucket(const QuotaErrorOr<BucketInfo>& result);
void OnBucketDeleted(
base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
callback,
QuotaErrorOr<mojom::BucketTableEntryPtr> result);
void DidGetQuotaSettingsForBucketCreation(
const BucketInitParams& bucket_params,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
const QuotaSettings& settings);
void DidGetBucket(bool notify_update_bucket,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
QuotaErrorOr<BucketInfo> result);
void DidGetBucketCheckExpiration(
const BucketInitParams& params,
base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
QuotaErrorOr<BucketInfo> result);
void DidGetBucketForDeletion(StatusCallback callback,
QuotaErrorOr<BucketInfo> result);
void DidGetBucketForUsage(QuotaClientType client_type,
int64_t delta,
base::Time modification_time,
base::OnceClosure callback,
QuotaErrorOr<BucketInfo> result);
void DidGetBucketForUsageAndQuota(UsageAndQuotaCallback callback,
QuotaErrorOr<BucketInfo> result);
void DidGetStorageKeys(GetStorageKeysCallback callback,
QuotaErrorOr<std::set<blink::StorageKey>> result);
void DidGetBuckets(
base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
QuotaErrorOr<std::set<BucketInfo>> result);
void DidGetBucketsCheckExpiration(
base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
QuotaErrorOr<std::set<BucketInfo>> result);
void DidGetModifiedBetween(GetBucketsCallback callback,
QuotaErrorOr<std::set<BucketLocator>> result);
void MaybeRunStoragePressureCallback(const blink::StorageKey& storage_key,
int64_t total_space,
int64_t available_space);
// Evaluates disk statistics to identify storage pressure
// (low disk space availability) and starts the storage
// pressure event dispatch if appropriate.
// TODO(crbug.com/1088004): Implement UsageAndQuotaInfoGatherer::Completed()
// to use DetermineStoragePressure().
void DetermineStoragePressure(int64_t free_space, int64_t total_space);
absl::optional<int64_t> GetQuotaOverrideForStorageKey(
const blink::StorageKey&);
template <typename ValueType>
void PostTaskAndReplyWithResultForDBThread(
base::OnceCallback<QuotaErrorOr<ValueType>(QuotaDatabase*)> task,
base::OnceCallback<void(QuotaErrorOr<ValueType>)> reply,
const base::Location& from_here = base::Location::Current(),
bool is_bootstrap_task = false);
void PostTaskAndReplyWithResultForDBThread(
base::OnceCallback<QuotaError(QuotaDatabase*)> task,
base::OnceCallback<void(QuotaError)> reply,
const base::Location& from_here = base::Location::Current(),
bool is_bootstrap_task = false);
static QuotaAvailability CallGetVolumeInfo(GetVolumeInfoFn get_volume_info_fn,
const base::FilePath& path);
static QuotaAvailability GetVolumeInfo(const base::FilePath& path);
const bool is_incognito_;
const base::FilePath profile_path_;
// This member is thread-safe. The scoped_refptr is immutable (the object it
// points to never changes), and the underlying object is thread-safe.
const scoped_refptr<QuotaManagerProxy> proxy_;
bool db_disabled_ = false;
bool eviction_disabled_ = false;
bool bootstrap_disabled_for_testing_ = false;
absl::optional<blink::StorageKey>
storage_key_for_pending_storage_pressure_callback_;
scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
scoped_refptr<base::SequencedTaskRunner> db_runner_;
// QuotaManagerImpl creates `database_` and later schedules it for deletion on
// `db_runner_`. Thus, `database_` may outlive `this`.
std::unique_ptr<QuotaDatabase> database_;
bool is_bootstrapping_database_ = false;
// Queued callbacks to QuotaDatabase that will run after database bootstrap is
// complete.
std::vector<base::OnceClosure> database_callbacks_;
GetQuotaSettingsFunc get_settings_function_;
scoped_refptr<base::TaskRunner> get_settings_task_runner_;
base::RepeatingCallback<void(const blink::StorageKey&)>
storage_pressure_callback_;
base::RepeatingClosure quota_change_callback_;
QuotaSettings settings_;
base::TimeTicks settings_timestamp_;
std::tuple<base::TimeTicks, int64_t, int64_t>
cached_disk_stats_for_storage_pressure_;
CallbackQueue<QuotaSettingsCallback, const QuotaSettings&>
settings_callbacks_;
CallbackQueue<StorageCapacityCallback, int64_t, int64_t>
storage_capacity_callbacks_;
// The storage key for the last time a bucket was opened. This is used as an
// imperfect estimate of which site may have encountered the last quota
// database full disk error.
absl::optional<blink::StorageKey> last_opened_bucket_site_;
// The last time that an eviction round was started due to a full disk error.
base::TimeTicks last_full_disk_eviction_time_;
// Buckets that have been notified of access during LRU task to exclude from
// eviction.
std::set<BucketLocator> access_notified_buckets_;
std::map<blink::StorageKey, QuotaOverride> devtools_overrides_;
int next_override_handle_id_ = 0;
// Serve mojo connections for chrome://quota-internals pages.
mojo::ReceiverSet<mojom::QuotaInternalsHandler> internals_handlers_receivers_
GUARDED_BY_CONTEXT(sequence_checker_);
// Owns the QuotaClient remotes registered via RegisterClient().
//
// Iterating over this list is almost always incorrect. Most algorithms should
// iterate over an entry in |client_types_|.
//
// TODO(crbug.com/1016065): Handle Storage Service crashes. Will likely entail
// using a mojo::RemoteSet here.
std::vector<mojo::Remote<mojom::QuotaClient>> clients_for_ownership_;
// Maps QuotaClient instances to client types.
//
// The QuotaClient instances pointed to by the map keys are guaranteed to be
// alive, because they are owned by `legacy_clients_for_ownership_`.
base::flat_map<blink::mojom::StorageType,
base::flat_map<mojom::QuotaClient*, QuotaClientType>>
client_types_;
std::unique_ptr<UsageTracker> temporary_usage_tracker_;
std::unique_ptr<UsageTracker> syncable_usage_tracker_;
// TODO(michaeln): Need a way to clear the cache, drop and
// reinstantiate the trackers when they're not handling requests.
std::unique_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_;
// Set when there is an eviction task in-flight.
bool is_getting_eviction_bucket_ = false;
// Map from bucket id to eviction error count.
std::map<BucketId, int> buckets_in_error_;
scoped_refptr<SpecialStoragePolicy> special_storage_policy_;
base::RepeatingTimer histogram_timer_;
// Pointer to the function used to get volume information. This is
// overwritten by QuotaManagerImplTest in order to attain deterministic
// reported values. The default value points to
// QuotaManagerImpl::GetVolumeInfo.
GetVolumeInfoFn get_volume_info_fn_;
std::unique_ptr<EvictionRoundInfoHelper> eviction_helper_;
std::map<BucketSetDataDeleter*, std::unique_ptr<BucketSetDataDeleter>>
bucket_set_data_deleters_;
std::map<BucketDataDeleter*, std::unique_ptr<BucketDataDeleter>>
bucket_data_deleters_;
std::unique_ptr<StorageKeyGathererTask> storage_key_gatherer_;
mojo::RemoteSet<storage::mojom::QuotaManagerObserver> observers_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<QuotaManagerImpl> weak_factory_{this};
};
} // namespace storage
#endif // STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_IMPL_H_