chromium/storage/browser/quota/quota_manager_impl.cc

// 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.

#include "storage/browser/quota/quota_manager_impl.h"

#include <stddef.h>
#include <stdint.h>

#include <algorithm>
#include <cstdint>
#include <functional>
#include <limits>
#include <memory>
#include <utility>

#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_callbacks.h"
#include "base/functional/concurrent_closures.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/not_fatal_until.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
#include "base/sequence_checker.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/system/sys_info.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/thread_annotations.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/types/pass_key.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/cpp/buckets/constants.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "sql/error_delegate_util.h"
#include "sql/sqlite_result_code.h"
#include "sql/sqlite_result_code_values.h"
#include "storage/browser/quota/client_usage_tracker.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_features.h"
#include "storage/browser/quota/quota_macros.h"
#include "storage/browser/quota/quota_manager_observer.mojom-forward.h"
#include "storage/browser/quota/quota_manager_observer.mojom.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/quota/quota_override_handle.h"
#include "storage/browser/quota/quota_temporary_storage_evictor.h"
#include "storage/browser/quota/usage_tracker.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h"
#include "third_party/blink/public/mojom/storage_key/storage_key.mojom.h"
#include "url/origin.h"

StorageKey;
StorageType;

namespace storage {

namespace {

// These values are used in UMA, so the list should be append-only.
enum class DatabaseDisabledReason {};

constexpr int64_t kReportHistogramInterval =;  // 1 hour

// Take action on write errors if there is <= 2% disk space
// available.
constexpr double kStoragePressureThresholdRatio =;

// Limit how frequently QuotaManagerImpl polls for free disk space when
// only using that information to identify storage pressure.
constexpr base::TimeDelta kStoragePressureCheckDiskStatsInterval =;

// Modifies a given value by a uniformly random amount from
// -percent to +percent.
int64_t RandomizeByPercent(int64_t value, int percent) {}

bool IsSupportedType(StorageType type) {}

bool IsSupportedIncognitoType(StorageType type) {}

void ReportDatabaseDisabledReason(DatabaseDisabledReason reason) {}

void DidGetUsageAndQuotaStripBreakdown(
    QuotaManagerImpl::UsageAndQuotaCallback callback,
    blink::mojom::QuotaStatusCode status,
    int64_t usage,
    int64_t quota,
    blink::mojom::UsageBreakdownPtr usage_breakdown) {}

void DidGetUsageAndQuotaStripOverride(
    QuotaManagerImpl::UsageAndQuotaWithBreakdownCallback callback,
    blink::mojom::QuotaStatusCode status,
    int64_t usage,
    int64_t quota,
    bool is_override_enabled,
    blink::mojom::UsageBreakdownPtr usage_breakdown) {}

}  // namespace

// Heuristics: assuming average cloud server allows a few Gigs storage
// on the server side and the storage needs to be shared for user data
// and by multiple apps.
int64_t QuotaManagerImpl::kSyncableStorageDefaultStorageKeyQuota =;

constexpr int64_t QuotaManagerImpl::kGBytes;
constexpr int64_t QuotaManagerImpl::kNoLimit;
constexpr int QuotaManagerImpl::kEvictionIntervalInMilliSeconds;
constexpr int QuotaManagerImpl::kThresholdOfErrorsToBeDenylisted;
constexpr int QuotaManagerImpl::kThresholdRandomizationPercent;
constexpr char QuotaManagerImpl::kDatabaseName[];
constexpr char QuotaManagerImpl::kEvictedBucketAccessedCountHistogram[];
constexpr char QuotaManagerImpl::kEvictedBucketDaysSinceAccessHistogram[];

QuotaManagerImpl::QuotaOverride::QuotaOverride() = default;
QuotaManagerImpl::QuotaOverride::~QuotaOverride() = default;

class QuotaManagerImpl::UsageAndQuotaInfoGatherer : public QuotaTask {};

class QuotaManagerImpl::EvictionRoundInfoHelper {};

class QuotaManagerImpl::GetUsageInfoTask : public QuotaTask {};

class QuotaManagerImpl::StorageKeyGathererTask {};

// Calls QuotaClients in `quota_client_types` for the `bucket` to delete bucket
// data. Will delete bucket entries from the QuotaDatabase if bucket data has
// been successfully deleted from all registered QuotaClient.
// This is currently only for the default bucket. If a non-default bucket is to
// be deleted, it will immediately complete the task since non-default bucket
// usage is not being tracked by QuotaClients yet.
class QuotaManagerImpl::BucketDataDeleter {};

// Deletes a set of buckets.
class QuotaManagerImpl::BucketSetDataDeleter {};

class QuotaManagerImpl::StorageCleanupHelper : public QuotaTask {};

// Gather storage key info table for quota-internals page.
//
// This class is granted ownership of itself when it is passed to
// DidDumpBucketTable() via base::Owned(). When the closure for said function
// goes out of scope, the object is deleted.
// This class is not thread-safe because there can be races when entries_ is
// modified.
class QuotaManagerImpl::DumpBucketTableHelper {};

// QuotaManagerImpl -----------------------------------------------------------

QuotaManagerImpl::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)
    :{}

void QuotaManagerImpl::SetQuotaSettings(const QuotaSettings& settings) {}

void QuotaManagerImpl::UpdateOrCreateBucket(
    const BucketInitParams& bucket_params,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::GetOrCreateBucketDeprecated(
    const BucketInitParams& bucket_params,
    blink::mojom::StorageType storage_type,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::CreateBucketForTesting(
    const StorageKey& storage_key,
    const std::string& bucket_name,
    blink::mojom::StorageType storage_type,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::GetBucketByNameUnsafe(
    const StorageKey& storage_key,
    const std::string& bucket_name,
    blink::mojom::StorageType type,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::GetBucketById(
    const BucketId& bucket_id,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::GetStorageKeysForType(blink::mojom::StorageType type,
                                             GetStorageKeysCallback callback) {}

void QuotaManagerImpl::GetBucketsForType(
    blink::mojom::StorageType type,
    base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback) {}

void QuotaManagerImpl::GetBucketsForHost(
    const std::string& host,
    blink::mojom::StorageType type,
    base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback) {}

void QuotaManagerImpl::GetBucketsForStorageKey(
    const StorageKey& storage_key,
    blink::mojom::StorageType type,
    base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
    bool delete_expired) {}

void QuotaManagerImpl::GetUsageInfo(GetUsageInfoCallback callback) {}

void QuotaManagerImpl::GetUsageAndQuotaForWebApps(
    const StorageKey& storage_key,
    StorageType type,
    UsageAndQuotaCallback callback) {}

void QuotaManagerImpl::GetUsageAndQuotaWithBreakdown(
    const StorageKey& storage_key,
    StorageType type,
    UsageAndQuotaWithBreakdownCallback callback) {}

void QuotaManagerImpl::GetUsageAndQuotaForDevtools(
    const StorageKey& storage_key,
    StorageType type,
    UsageAndQuotaForDevtoolsCallback callback) {}

void QuotaManagerImpl::GetUsageAndQuota(const StorageKey& storage_key,
                                        StorageType type,
                                        UsageAndQuotaCallback callback) {}

void QuotaManagerImpl::GetBucketUsageAndQuota(BucketId id,
                                              UsageAndQuotaCallback callback) {}

void QuotaManagerImpl::GetBucketSpaceRemaining(
    const BucketLocator& bucket,
    base::OnceCallback<void(QuotaErrorOr<int64_t>)> callback) {}

void QuotaManagerImpl::OnClientWriteFailed(const StorageKey& storage_key) {}

void QuotaManagerImpl::SetUsageCacheEnabled(QuotaClientType client_id,
                                            const StorageKey& storage_key,
                                            StorageType type,
                                            bool enabled) {}

void QuotaManagerImpl::DeleteBucketData(const BucketLocator& bucket,
                                        QuotaClientTypes quota_client_types,
                                        StatusCallback callback) {}

void QuotaManagerImpl::FindAndDeleteBucketData(const StorageKey& storage_key,
                                               const std::string& bucket_name,
                                               StatusCallback callback) {}

void QuotaManagerImpl::UpdateBucketExpiration(
    BucketId bucket,
    const base::Time& expiration,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::UpdateBucketPersistence(
    BucketId bucket,
    bool persistent,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback) {}

void QuotaManagerImpl::PerformStorageCleanup(
    StorageType type,
    QuotaClientTypes quota_client_types,
    base::OnceClosure callback) {}

void QuotaManagerImpl::DeleteHostData(const std::string& host,
                                      StorageType type,
                                      StatusCallback callback) {}

void QuotaManagerImpl::DeleteStorageKeyData(
    const blink::StorageKey& storage_key,
    blink::mojom::StorageType type,
    StatusCallback callback) {}

// static
void QuotaManagerImpl::DidDeleteBuckets(
    base::WeakPtr<QuotaManagerImpl> quota_manager,
    StatusCallback callback,
    BucketSetDataDeleter* deleter,
    blink::mojom::QuotaStatusCode status_code) {}

void QuotaManagerImpl::BindInternalsHandler(
    mojo::PendingReceiver<mojom::QuotaInternalsHandler> receiver) {}

void QuotaManagerImpl::GetDiskAvailabilityAndTempPoolSize(
    GetDiskAvailabilityAndTempPoolSizeCallback callback) {}

void QuotaManagerImpl::UpdateQuotaInternalsDiskAvailability(
    base::OnceClosure barrier_callback,
    AccumulateQuotaInternalsInfo* info,
    int64_t total_space,
    int64_t available_space) {}

void QuotaManagerImpl::UpdateQuotaInternalsTempPoolSpace(
    base::OnceClosure barrier_callback,
    AccumulateQuotaInternalsInfo* info,
    const QuotaSettings& settings) {}

void QuotaManagerImpl::FinallySendDiskAvailabilityAndTempPoolSize(
    GetDiskAvailabilityAndTempPoolSizeCallback callback,
    std::unique_ptr<AccumulateQuotaInternalsInfo> info) {}

void QuotaManagerImpl::GetStatistics(GetStatisticsCallback callback) {}

void QuotaManagerImpl::GetGlobalUsage(StorageType type,
                                      UsageCallback callback) {}

void QuotaManagerImpl::GetGlobalUsageForInternals(
    blink::mojom::StorageType storage_type,
    GetGlobalUsageForInternalsCallback callback) {}

void QuotaManagerImpl::GetStorageKeyUsageWithBreakdown(
    const blink::StorageKey& storage_key,
    StorageType type,
    UsageWithBreakdownCallback callback) {}

void QuotaManagerImpl::GetBucketUsageWithBreakdown(
    const BucketLocator& bucket,
    UsageWithBreakdownCallback callback) {}

bool QuotaManagerImpl::IsStorageUnlimited(const StorageKey& storage_key,
                                          StorageType type) const {}

int64_t QuotaManagerImpl::GetQuotaForStorageKey(
    const StorageKey& storage_key,
    StorageType type,
    const QuotaSettings& settings) const {}

void QuotaManagerImpl::GetBucketsModifiedBetween(StorageType type,
                                                 base::Time begin,
                                                 base::Time end,
                                                 GetBucketsCallback callback) {}

bool QuotaManagerImpl::ResetUsageTracker(StorageType type) {}

QuotaManagerImpl::~QuotaManagerImpl() {}

void QuotaManagerImpl::EnsureDatabaseOpened() {}

void QuotaManagerImpl::MaybeBootstrapDatabase() {}

void QuotaManagerImpl::DidGetBootstrapFlag(bool is_database_bootstrapped) {}

void QuotaManagerImpl::BootstrapDatabase() {}

void QuotaManagerImpl::DidGetStorageKeysForBootstrap(
    StorageKeysByType storage_keys_by_type) {}

void QuotaManagerImpl::DidBootstrapDatabase(QuotaError error) {}

void QuotaManagerImpl::DidSetDatabaseBootstrapped(QuotaError error) {}

void QuotaManagerImpl::RunDatabaseCallbacks() {}

void QuotaManagerImpl::RegisterClient(
    mojo::PendingRemote<mojom::QuotaClient> client,
    QuotaClientType client_type,
    const std::vector<blink::mojom::StorageType>& storage_types) {}

UsageTracker* QuotaManagerImpl::GetUsageTracker(StorageType type) const {}

void QuotaManagerImpl::NotifyBucketAccessed(const BucketLocator& bucket,
                                            base::Time access_time) {}

void QuotaManagerImpl::NotifyBucketModified(QuotaClientType client_id,
                                            const BucketLocator& bucket,
                                            std::optional<int64_t> delta,
                                            base::Time modification_time,
                                            base::OnceClosure callback) {}

void QuotaManagerImpl::DumpBucketTable(DumpBucketTableCallback callback) {}

void QuotaManagerImpl::RetrieveBucketsTable(
    RetrieveBucketsTableCallback callback) {}

void QuotaManagerImpl::RetrieveBucketUsageForBucketTable(
    RetrieveBucketsTableCallback callback,
    BucketTableEntries entries) {}

void QuotaManagerImpl::AddBucketTableEntry(
    mojom::BucketTableEntryPtr entry,
    base::OnceCallback<void(mojom::BucketTableEntryPtr)> callback,
    int64_t usage,
    blink::mojom::UsageBreakdownPtr bucket_usage_breakdown) {}

void QuotaManagerImpl::OnDbError(int error_code) {}

void QuotaManagerImpl::OnFullDiskError(std::optional<StorageKey> storage_key) {}

void QuotaManagerImpl::NotifyWriteFailed(const blink::StorageKey& storage_key) {}

void QuotaManagerImpl::StartEviction() {}

void QuotaManagerImpl::DeleteBucketFromDatabase(
    const BucketLocator& bucket,
    bool commit_immediately,
    base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
        callback) {}

void QuotaManagerImpl::DidEvictBucketData(
    BucketId evicted_bucket_id,
    base::RepeatingCallback<void(bool)> barrier,
    QuotaErrorOr<mojom::BucketTableEntryPtr> entry) {}

void QuotaManagerImpl::DeleteBucketDataInternal(
    const BucketLocator& bucket,
    QuotaClientTypes quota_client_types,
    base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)>
        callback) {}

// static
void QuotaManagerImpl::DidDeleteBucketData(
    base::WeakPtr<QuotaManagerImpl> quota_manager,
    base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)> callback,
    BucketDataDeleter* deleter,
    QuotaErrorOr<mojom::BucketTableEntryPtr> result) {}

void QuotaManagerImpl::DidDeleteBucketForRecreation(
    const BucketInitParams& params,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
    BucketInfo bucket_info,
    QuotaErrorOr<mojom::BucketTableEntryPtr> result) {}

void QuotaManagerImpl::MaybeRunStoragePressureCallback(
    const StorageKey& storage_key,
    int64_t total_space,
    int64_t available_space) {}

void QuotaManagerImpl::SimulateStoragePressure(const url::Origin& origin_url) {}

void QuotaManagerImpl::IsSimulateStoragePressureAvailable(
    IsSimulateStoragePressureAvailableCallback callback) {}

void QuotaManagerImpl::DetermineStoragePressure(int64_t total_space,
                                                int64_t free_space) {}

void QuotaManagerImpl::SetStoragePressureCallback(
    base::RepeatingCallback<void(const StorageKey&)>
        storage_pressure_callback) {}

int QuotaManagerImpl::GetOverrideHandleId() {}

void QuotaManagerImpl::OverrideQuotaForStorageKey(
    int handle_id,
    const StorageKey& storage_key,
    std::optional<int64_t> quota_size) {}

void QuotaManagerImpl::WithdrawOverridesForHandle(int handle_id) {}

std::optional<int64_t> QuotaManagerImpl::GetQuotaOverrideForStorageKey(
    const StorageKey& storage_key) {}

void QuotaManagerImpl::SetQuotaChangeCallbackForTesting(
    base::RepeatingClosure storage_pressure_event_callback) {}

void QuotaManagerImpl::CorruptDatabaseForTesting(
    base::OnceCallback<void(const base::FilePath&)> corrupter,
    base::OnceCallback<void(QuotaError)> callback) {}

void QuotaManagerImpl::ReportHistogram() {}

void QuotaManagerImpl::DidGetTemporaryGlobalUsageForHistogram(
    int64_t usage,
    int64_t unlimited_usage) {}

void QuotaManagerImpl::DidGetStorageCapacityForHistogram(
    int64_t usage,
    int64_t total_space,
    int64_t available_space) {}

void QuotaManagerImpl::DidDumpBucketTableForHistogram(
    BucketTableEntries entries) {}

std::set<BucketId> QuotaManagerImpl::GetEvictionBucketExceptions() {}

void QuotaManagerImpl::DidGetEvictionBuckets(
    GetBucketsCallback callback,
    const std::set<BucketLocator>& buckets) {}

void QuotaManagerImpl::GetEvictionBuckets(int64_t target_usage,
                                          GetBucketsCallback callback) {}

void QuotaManagerImpl::EvictExpiredBuckets(StatusCallback done) {}

void QuotaManagerImpl::EvictBucketData(
    const std::set<BucketLocator>& buckets,
    base::OnceCallback<void(int)> on_eviction_done) {}

void QuotaManagerImpl::GetEvictionRoundInfo(
    EvictionRoundInfoCallback callback) {}

void QuotaManagerImpl::DidGetEvictionRoundInfo() {}

void QuotaManagerImpl::GetBucketsForEvictionFromDatabase(
    int64_t target_usage,
    std::map<BucketLocator, int64_t> usage_map,
    GetBucketsCallback callback) {}

void QuotaManagerImpl::DidGetBucketsForEvictionFromDatabase(
    GetBucketsCallback callback,
    QuotaErrorOr<std::set<BucketLocator>> result) {}

void QuotaManagerImpl::GetQuotaSettings(QuotaSettingsCallback callback) {}

void QuotaManagerImpl::DidGetSettings(std::optional<QuotaSettings> settings) {}

void QuotaManagerImpl::GetStorageCapacity(StorageCapacityCallback callback) {}

void QuotaManagerImpl::ContinueIncognitoGetStorageCapacity(
    const QuotaSettings& settings) {}

void QuotaManagerImpl::DidGetStorageCapacity(
    const QuotaAvailability& quota_usage) {}

void QuotaManagerImpl::DidRecoverOrRazeForReBootstrap(bool success) {}

void QuotaManagerImpl::NotifyUpdatedBucket(
    const QuotaErrorOr<BucketInfo>& result) {}

void QuotaManagerImpl::OnBucketDeleted(
    base::OnceCallback<void(QuotaErrorOr<mojom::BucketTableEntryPtr>)> callback,
    QuotaErrorOr<mojom::BucketTableEntryPtr> result) {}

void QuotaManagerImpl::DidGetQuotaSettingsForBucketCreation(
    const BucketInitParams& bucket_params,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
    const QuotaSettings& settings) {}

void QuotaManagerImpl::DidGetBucket(
    bool notify_update_bucket,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
    QuotaErrorOr<BucketInfo> result) {}

void QuotaManagerImpl::DidGetBucketCheckExpiration(
    const BucketInitParams& params,
    base::OnceCallback<void(QuotaErrorOr<BucketInfo>)> callback,
    QuotaErrorOr<BucketInfo> result) {}

void QuotaManagerImpl::DidGetBucketForDeletion(
    StatusCallback callback,
    QuotaErrorOr<BucketInfo> result) {}

void QuotaManagerImpl::DidGetBucketForUsageAndQuota(
    UsageAndQuotaCallback callback,
    QuotaErrorOr<BucketInfo> result) {}

void QuotaManagerImpl::DidGetStorageKeys(
    GetStorageKeysCallback callback,
    QuotaErrorOr<std::set<StorageKey>> result) {}

void QuotaManagerImpl::DidGetBuckets(
    base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
    QuotaErrorOr<std::set<BucketInfo>> result) {}

void QuotaManagerImpl::DidGetBucketsCheckExpiration(
    base::OnceCallback<void(QuotaErrorOr<std::set<BucketInfo>>)> callback,
    QuotaErrorOr<std::set<BucketInfo>> result) {}

void QuotaManagerImpl::DidGetModifiedBetween(
    GetBucketsCallback callback,
    QuotaErrorOr<std::set<BucketLocator>> result) {}

template <typename ValueType>
void QuotaManagerImpl::PostTaskAndReplyWithResultForDBThread(
    base::OnceCallback<QuotaErrorOr<ValueType>(QuotaDatabase*)> task,
    base::OnceCallback<void(QuotaErrorOr<ValueType>)> reply,
    const base::Location& from_here,
    bool is_bootstrap_task) {}

void QuotaManagerImpl::PostTaskAndReplyWithResultForDBThread(
    base::OnceCallback<QuotaError(QuotaDatabase*)> task,
    base::OnceCallback<void(QuotaError)> reply,
    const base::Location& from_here,
    bool is_bootstrap_task) {}

// static
QuotaAvailability QuotaManagerImpl::CallGetVolumeInfo(
    GetVolumeInfoFn get_volume_info_fn,
    const base::FilePath& path) {}

// static
QuotaAvailability QuotaManagerImpl::GetVolumeInfo(const base::FilePath& path) {}

void QuotaManagerImpl::AddObserver(
    mojo::PendingRemote<storage::mojom::QuotaManagerObserver> observer) {}
}  // namespace storage