/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "QuotaManagerService.h" // Local includes #include "ActorsChild.h" #include "Client.h" #include "QuotaManager.h" #include "QuotaRequests.h" // Global includes #include #include #include #include "MainThreadUtils.h" #include "mozilla/Assertions.h" #include "mozilla/Atomics.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/Hal.h" #include "mozilla/MacroForEach.h" #include "mozilla/Maybe.h" #include "mozilla/OriginAttributes.h" #include "mozilla/RefPtr.h" #include "mozilla/Services.h" #include "mozilla/StaticPrefs_dom.h" #include "mozilla/StaticPtr.h" #include "mozilla/Unused.h" #include "mozilla/Variant.h" #include "mozilla/dom/quota/PQuota.h" #include "mozilla/dom/quota/PersistenceType.h" #include "mozilla/dom/quota/ResultExtensions.h" #include "mozilla/fallible.h" #include "mozilla/hal_sandbox/PHal.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" #include "nsDebug.h" #include "nsError.h" #include "nsIObserverService.h" #include "nsIPrincipal.h" #include "nsIUserIdleService.h" #include "nsServiceManagerUtils.h" #include "nsStringFwd.h" #include "nsXULAppAPI.h" #include "nscore.h" #define PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID "profile-before-change-qm" namespace mozilla::dom::quota { using namespace mozilla::ipc; namespace { const char kIdleServiceContractId[] = "@mozilla.org/widget/useridleservice;1"; // The number of seconds we will wait after receiving the idle-daily // notification before beginning maintenance. const uint32_t kIdleObserverTimeSec = 1; mozilla::StaticRefPtr gQuotaManagerService; mozilla::Atomic gInitialized(false); mozilla::Atomic gClosed(false); nsresult CheckedPrincipalToPrincipalInfo(nsIPrincipal* aPrincipal, PrincipalInfo& aPrincipalInfo) { MOZ_ASSERT(aPrincipal); nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &aPrincipalInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo))) { return NS_ERROR_FAILURE; } if (aPrincipalInfo.type() != PrincipalInfo::TContentPrincipalInfo && aPrincipalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) { return NS_ERROR_UNEXPECTED; } return NS_OK; } nsresult GetClearResetOriginParams(nsIPrincipal* aPrincipal, const nsACString& aPersistenceType, const nsAString& aClientType, ClearResetOriginParams& aParams) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, aParams.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (aPersistenceType.IsVoid()) { aParams.persistenceTypeIsExplicit() = false; } else { const auto maybePersistenceType = PersistenceTypeFromString(aPersistenceType, fallible); if (NS_WARN_IF(maybePersistenceType.isNothing())) { return NS_ERROR_INVALID_ARG; } aParams.persistenceType() = maybePersistenceType.value(); aParams.persistenceTypeIsExplicit() = true; } if (aClientType.IsVoid()) { aParams.clientTypeIsExplicit() = false; } else { Client::Type clientType; bool ok = Client::TypeFromText(aClientType, clientType, fallible); if (NS_WARN_IF(!ok)) { return NS_ERROR_INVALID_ARG; } aParams.clientType() = clientType; aParams.clientTypeIsExplicit() = true; } return NS_OK; } } // namespace class QuotaManagerService::PendingRequestInfo { protected: RefPtr mRequest; public: explicit PendingRequestInfo(RequestBase* aRequest) : mRequest(aRequest) {} virtual ~PendingRequestInfo() = default; RequestBase* GetRequest() const { return mRequest; } virtual nsresult InitiateRequest(QuotaChild* aActor) = 0; }; class QuotaManagerService::UsageRequestInfo : public PendingRequestInfo { UsageRequestParams mParams; public: UsageRequestInfo(UsageRequest* aRequest, const UsageRequestParams& aParams) : PendingRequestInfo(aRequest), mParams(aParams) { MOZ_ASSERT(aRequest); MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); } virtual nsresult InitiateRequest(QuotaChild* aActor) override; }; class QuotaManagerService::RequestInfo : public PendingRequestInfo { RequestParams mParams; public: RequestInfo(Request* aRequest, const RequestParams& aParams) : PendingRequestInfo(aRequest), mParams(aParams) { MOZ_ASSERT(aRequest); MOZ_ASSERT(aParams.type() != RequestParams::T__None); } virtual nsresult InitiateRequest(QuotaChild* aActor) override; }; class QuotaManagerService::IdleMaintenanceInfo : public PendingRequestInfo { const bool mStart; public: explicit IdleMaintenanceInfo(bool aStart) : PendingRequestInfo(nullptr), mStart(aStart) {} virtual nsresult InitiateRequest(QuotaChild* aActor) override; }; QuotaManagerService::QuotaManagerService() : mBackgroundActor(nullptr), mBackgroundActorFailed(false), mIdleObserverRegistered(false) { MOZ_ASSERT(NS_IsMainThread()); } QuotaManagerService::~QuotaManagerService() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mIdleObserverRegistered); } // static QuotaManagerService* QuotaManagerService::GetOrCreate() { MOZ_ASSERT(NS_IsMainThread()); if (gClosed) { MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!"); return nullptr; } if (!gQuotaManagerService) { RefPtr instance(new QuotaManagerService()); nsresult rv = instance->Init(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } if (gInitialized.exchange(true)) { MOZ_ASSERT(false, "Initialized more than once?!"); } gQuotaManagerService = instance; ClearOnShutdown(&gQuotaManagerService); } return gQuotaManagerService; } // static QuotaManagerService* QuotaManagerService::Get() { // Does not return an owning reference. return gQuotaManagerService; } // static already_AddRefed QuotaManagerService::FactoryCreate() { RefPtr quotaManagerService = GetOrCreate(); return quotaManagerService.forget(); } void QuotaManagerService::ClearBackgroundActor() { MOZ_ASSERT(NS_IsMainThread()); mBackgroundActor = nullptr; } void QuotaManagerService::AbortOperationsForProcess( ContentParentId aContentParentId) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); nsresult rv = EnsureBackgroundActor(); if (NS_WARN_IF(NS_FAILED(rv))) { return; } if (NS_WARN_IF( !mBackgroundActor->SendAbortOperationsForProcess(aContentParentId))) { return; } } nsresult QuotaManagerService::Init() { MOZ_ASSERT(NS_IsMainThread()); if (XRE_IsParentProcess()) { nsCOMPtr observerService = mozilla::services::GetObserverService(); if (NS_WARN_IF(!observerService)) { return NS_ERROR_FAILURE; } nsresult rv = observerService->AddObserver( this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } return NS_OK; } void QuotaManagerService::Destroy() { // Setting the closed flag prevents the service from being recreated. // Don't set it though if there's no real instance created. if (gInitialized && gClosed.exchange(true)) { MOZ_ASSERT(false, "Shutdown more than once?!"); } delete this; } nsresult QuotaManagerService::EnsureBackgroundActor() { MOZ_ASSERT(NS_IsMainThread()); // Nothing can be done here if we have previously failed to create a // background actor. if (mBackgroundActorFailed) { return NS_ERROR_FAILURE; } if (!mBackgroundActor) { PBackgroundChild* backgroundActor = BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!backgroundActor)) { mBackgroundActorFailed = true; return NS_ERROR_FAILURE; } { QuotaChild* actor = new QuotaChild(this); mBackgroundActor = static_cast( backgroundActor->SendPQuotaConstructor(actor)); } } if (!mBackgroundActor) { mBackgroundActorFailed = true; return NS_ERROR_FAILURE; } return NS_OK; } nsresult QuotaManagerService::InitiateRequest(PendingRequestInfo& aInfo) { nsresult rv = EnsureBackgroundActor(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = aInfo.InitiateRequest(mBackgroundActor); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } void QuotaManagerService::PerformIdleMaintenance() { using namespace mozilla::hal; MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); // If we're running on battery power then skip all idle maintenance since we // would otherwise be doing lots of disk I/O. BatteryInformation batteryInfo; #ifdef MOZ_WIDGET_ANDROID // Android XPCShell doesn't load the AndroidBridge that is needed to make // GetCurrentBatteryInformation work... if (!QuotaManager::IsRunningXPCShellTests()) #endif { // In order to give the correct battery level, hal must have registered // battery observers. RegisterBatteryObserver(this); GetCurrentBatteryInformation(&batteryInfo); UnregisterBatteryObserver(this); } // If we're running XPCShell because we always want to be able to test this // code so pretend that we're always charging. if (QuotaManager::IsRunningXPCShellTests()) { batteryInfo.level() = 100; batteryInfo.charging() = true; } if (NS_WARN_IF(!batteryInfo.charging())) { return; } if (QuotaManager::IsRunningXPCShellTests()) { // We don't want user activity to impact this code if we're running tests. Unused << Observe(nullptr, OBSERVER_TOPIC_IDLE, nullptr); } else if (!mIdleObserverRegistered) { nsCOMPtr idleService = do_GetService(kIdleServiceContractId); MOZ_ASSERT(idleService); MOZ_ALWAYS_SUCCEEDS( idleService->AddIdleObserver(this, kIdleObserverTimeSec)); mIdleObserverRegistered = true; } } void QuotaManagerService::RemoveIdleObserver() { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); if (mIdleObserverRegistered) { nsCOMPtr idleService = do_GetService(kIdleServiceContractId); MOZ_ASSERT(idleService); // Ignore the return value of RemoveIdleObserver, it may fail if the // observer has already been unregistered during shutdown. Unused << idleService->RemoveIdleObserver(this, kIdleObserverTimeSec); mIdleObserverRegistered = false; } } NS_IMPL_ADDREF(QuotaManagerService) NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService, Destroy()) NS_IMPL_QUERY_INTERFACE(QuotaManagerService, nsIQuotaManagerService, nsIObserver) NS_IMETHODIMP QuotaManagerService::StorageName(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); StorageNameParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::StorageInitialized(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); StorageInitializedParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::TemporaryStorageInitialized(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); TemporaryStorageInitializedParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Init(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); InitParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::InitTemporaryStorage(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); InitTemporaryStorageParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::InitializePersistentOrigin(nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); InitializePersistentOriginParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::InitializeTemporaryOrigin( const nsACString& aPersistenceType, nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); InitializeTemporaryOriginParams params; const auto maybePersistenceType = PersistenceTypeFromString(aPersistenceType, fallible); if (NS_WARN_IF(maybePersistenceType.isNothing())) { return NS_ERROR_INVALID_ARG; } if (NS_WARN_IF(!IsBestEffortPersistenceType(maybePersistenceType.value()))) { return NS_ERROR_FAILURE; } params.persistenceType() = maybePersistenceType.value(); nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::GetFullOriginMetadata(const nsACString& aPersistenceType, nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(nsContentUtils::IsCallerChrome()); QM_TRY(OkIf(StaticPrefs::dom_quotaManager_testing()), NS_ERROR_UNEXPECTED); const auto maybePersistenceType = PersistenceTypeFromString(aPersistenceType, fallible); QM_TRY(OkIf(maybePersistenceType.isSome()), NS_ERROR_INVALID_ARG); QM_TRY(OkIf(IsBestEffortPersistenceType(*maybePersistenceType)), NS_ERROR_INVALID_ARG); PrincipalInfo principalInfo; QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(aPrincipal, &principalInfo))); QM_TRY(OkIf(QuotaManager::IsPrincipalInfoValid(principalInfo)), NS_ERROR_INVALID_ARG); RefPtr request = new Request(); GetFullOriginMetadataParams params; params.persistenceType() = *maybePersistenceType; params.principalInfo() = std::move(principalInfo); RequestInfo info(request, params); QM_TRY(MOZ_TO_RESULT(InitiateRequest(info))); request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback, bool aGetAll, nsIQuotaUsageRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aCallback); RefPtr request = new UsageRequest(aCallback); AllUsageParams params; params.getAll() = aGetAll; UsageRequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, bool aFromMemory, nsIQuotaUsageRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); RefPtr request = new UsageRequest(aPrincipal, aCallback); OriginUsageParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } params.fromMemory() = aFromMemory; UsageRequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Clear(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); ClearAllParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::ClearStoragesForPrivateBrowsing( nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); RefPtr request = new Request(); ClearPrivateBrowsingParams params; RequestInfo info(request, params); QM_TRY(MOZ_TO_RESULT(InitiateRequest(info))); request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::ClearStoragesForOriginAttributesPattern( const nsAString& aPattern, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); OriginAttributesPattern pattern; MOZ_ALWAYS_TRUE(pattern.Init(aPattern)); RefPtr request = new Request(); ClearDataParams params; params.pattern() = pattern; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::ClearStoragesForPrincipal( nsIPrincipal* aPrincipal, const nsACString& aPersistenceType, const nsAString& aClientType, bool aClearAll, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); nsCString suffix; aPrincipal->OriginAttributesRef().CreateSuffix(suffix); if (NS_WARN_IF(aClearAll && !suffix.IsEmpty())) { // The originAttributes should be default originAttributes when the // aClearAll flag is set. return NS_ERROR_INVALID_ARG; } RefPtr request = new Request(aPrincipal); ClearResetOriginParams commonParams; nsresult rv = GetClearResetOriginParams(aPrincipal, aPersistenceType, aClientType, commonParams); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } ClearOriginParams params; params.commonParams() = std::move(commonParams); params.matchAll() = aClearAll; RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Reset(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(); ResetAllParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::ResetStoragesForPrincipal( nsIPrincipal* aPrincipal, const nsACString& aPersistenceType, const nsAString& aClientType, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) { return NS_ERROR_UNEXPECTED; } RefPtr request = new Request(aPrincipal); ClearResetOriginParams commonParams; nsresult rv = GetClearResetOriginParams(aPrincipal, aPersistenceType, aClientType, commonParams); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestParams params; params = ResetOriginParams(commonParams); RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Persisted(nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(_retval); RefPtr request = new Request(aPrincipal); PersistedParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Persist(nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(_retval); RefPtr request = new Request(aPrincipal); PersistParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Estimate(nsIPrincipal* aPrincipal, nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipal); RefPtr request = new Request(aPrincipal); EstimateParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } RequestInfo info(request, params); rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::ListOrigins(nsIQuotaRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); RefPtr request = new Request(); ListOriginsParams params; RequestInfo info(request, params); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } request.forget(_retval); return NS_OK; } NS_IMETHODIMP QuotaManagerService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); if (!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID)) { RemoveIdleObserver(); return NS_OK; } if (!strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) { PerformIdleMaintenance(); return NS_OK; } if (!strcmp(aTopic, OBSERVER_TOPIC_IDLE)) { IdleMaintenanceInfo info(/* aStart */ true); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } if (!strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) { RemoveIdleObserver(); IdleMaintenanceInfo info(/* aStart */ false); nsresult rv = InitiateRequest(info); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } MOZ_ASSERT_UNREACHABLE("Should never get here!"); return NS_OK; } void QuotaManagerService::Notify(const hal::BatteryInformation& aBatteryInfo) { // This notification is received when battery data changes. We don't need to // deal with this notification. } nsresult QuotaManagerService::UsageRequestInfo::InitiateRequest( QuotaChild* aActor) { MOZ_ASSERT(aActor); auto request = static_cast(mRequest.get()); auto actor = new QuotaUsageRequestChild(request); if (!aActor->SendPQuotaUsageRequestConstructor(actor, mParams)) { request->SetError(NS_ERROR_FAILURE); return NS_ERROR_FAILURE; } request->SetBackgroundActor(actor); return NS_OK; } nsresult QuotaManagerService::RequestInfo::InitiateRequest(QuotaChild* aActor) { MOZ_ASSERT(aActor); auto request = static_cast(mRequest.get()); auto actor = new QuotaRequestChild(request); if (!aActor->SendPQuotaRequestConstructor(actor, mParams)) { request->SetError(NS_ERROR_FAILURE); return NS_ERROR_FAILURE; } return NS_OK; } nsresult QuotaManagerService::IdleMaintenanceInfo::InitiateRequest( QuotaChild* aActor) { MOZ_ASSERT(aActor); bool result; if (mStart) { result = aActor->SendStartIdleMaintenance(); } else { result = aActor->SendStopIdleMaintenance(); } if (!result) { return NS_ERROR_FAILURE; } return NS_OK; } } // namespace mozilla::dom::quota