1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "QuotaManagerService.h"
10 #include "ActorsChild.h"
12 #include "QuotaManager.h"
13 #include "QuotaRequests.h"
19 #include "MainThreadUtils.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/ClearOnShutdown.h"
23 #include "mozilla/Hal.h"
24 #include "mozilla/MacroForEach.h"
25 #include "mozilla/Maybe.h"
26 #include "mozilla/OriginAttributes.h"
27 #include "mozilla/RefPtr.h"
28 #include "mozilla/Services.h"
29 #include "mozilla/StaticPrefs_dom.h"
30 #include "mozilla/StaticPtr.h"
31 #include "mozilla/Unused.h"
32 #include "mozilla/Variant.h"
33 #include "mozilla/dom/quota/PQuota.h"
34 #include "mozilla/dom/quota/PersistenceType.h"
35 #include "mozilla/dom/quota/ResultExtensions.h"
36 #include "mozilla/fallible.h"
37 #include "mozilla/hal_sandbox/PHal.h"
38 #include "mozilla/ipc/BackgroundChild.h"
39 #include "mozilla/ipc/BackgroundUtils.h"
40 #include "mozilla/ipc/PBackgroundChild.h"
41 #include "mozilla/ipc/PBackgroundSharedTypes.h"
43 #include "nsContentUtils.h"
46 #include "nsIObserverService.h"
47 #include "nsIPrincipal.h"
48 #include "nsIUserIdleService.h"
49 #include "nsServiceManagerUtils.h"
50 #include "nsStringFwd.h"
51 #include "nsVariant.h"
52 #include "nsXULAppAPI.h"
55 #define PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID "profile-before-change-qm"
57 namespace mozilla::dom::quota
{
59 using namespace mozilla::ipc
;
63 const char kIdleServiceContractId
[] = "@mozilla.org/widget/useridleservice;1";
65 // The number of seconds we will wait after receiving the idle-daily
66 // notification before beginning maintenance.
67 const uint32_t kIdleObserverTimeSec
= 1;
69 mozilla::StaticRefPtr
<QuotaManagerService
> gQuotaManagerService
;
71 mozilla::Atomic
<bool> gInitialized(false);
72 mozilla::Atomic
<bool> gClosed(false);
74 nsresult
CheckedPrincipalToPrincipalInfo(nsIPrincipal
* aPrincipal
,
75 PrincipalInfo
& aPrincipalInfo
) {
76 MOZ_ASSERT(aPrincipal
);
78 nsresult rv
= PrincipalToPrincipalInfo(aPrincipal
, &aPrincipalInfo
);
79 if (NS_WARN_IF(NS_FAILED(rv
))) {
83 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo
))) {
84 return NS_ERROR_FAILURE
;
87 if (aPrincipalInfo
.type() != PrincipalInfo::TContentPrincipalInfo
&&
88 aPrincipalInfo
.type() != PrincipalInfo::TSystemPrincipalInfo
) {
89 return NS_ERROR_UNEXPECTED
;
95 nsresult
GetClearResetOriginParams(nsIPrincipal
* aPrincipal
,
96 const nsACString
& aPersistenceType
,
97 const nsAString
& aClientType
,
98 ClearResetOriginParams
& aParams
) {
99 MOZ_ASSERT(NS_IsMainThread());
100 MOZ_ASSERT(aPrincipal
);
103 CheckedPrincipalToPrincipalInfo(aPrincipal
, aParams
.principalInfo());
104 if (NS_WARN_IF(NS_FAILED(rv
))) {
108 if (aPersistenceType
.IsVoid()) {
109 aParams
.persistenceTypeIsExplicit() = false;
111 const auto maybePersistenceType
=
112 PersistenceTypeFromString(aPersistenceType
, fallible
);
113 if (NS_WARN_IF(maybePersistenceType
.isNothing())) {
114 return NS_ERROR_INVALID_ARG
;
117 aParams
.persistenceType() = maybePersistenceType
.value();
118 aParams
.persistenceTypeIsExplicit() = true;
121 if (aClientType
.IsVoid()) {
122 aParams
.clientTypeIsExplicit() = false;
124 Client::Type clientType
;
125 bool ok
= Client::TypeFromText(aClientType
, clientType
, fallible
);
126 if (NS_WARN_IF(!ok
)) {
127 return NS_ERROR_INVALID_ARG
;
130 aParams
.clientType() = clientType
;
131 aParams
.clientTypeIsExplicit() = true;
137 class BoolResponsePromiseResolveOrRejectCallback
{
139 using PromiseType
= BoolResponsePromise
;
140 using RequestType
= Request
;
142 explicit BoolResponsePromiseResolveOrRejectCallback(
143 RefPtr
<RequestType
> aRequest
)
144 : mRequest(std::move(aRequest
)) {}
146 void operator()(const PromiseType::ResolveOrRejectValue
& aValue
) {
147 if (aValue
.IsResolve()) {
148 const BoolResponse
& response
= aValue
.ResolveValue();
150 switch (response
.type()) {
151 case BoolResponse::Tnsresult
:
152 mRequest
->SetError(response
.get_nsresult());
155 case BoolResponse::Tbool
: {
156 RefPtr
<nsVariant
> variant
= new nsVariant();
157 variant
->SetAsBool(response
.get_bool());
159 mRequest
->SetResult(variant
);
163 MOZ_CRASH("Unknown response type!");
167 mRequest
->SetError(NS_ERROR_FAILURE
);
172 RefPtr
<RequestType
> mRequest
;
177 class QuotaManagerService::PendingRequestInfo
{
179 RefPtr
<RequestBase
> mRequest
;
182 explicit PendingRequestInfo(RequestBase
* aRequest
) : mRequest(aRequest
) {}
184 virtual ~PendingRequestInfo() = default;
186 RequestBase
* GetRequest() const { return mRequest
; }
188 virtual nsresult
InitiateRequest(QuotaChild
* aActor
) = 0;
191 class QuotaManagerService::UsageRequestInfo
: public PendingRequestInfo
{
192 UsageRequestParams mParams
;
195 UsageRequestInfo(UsageRequest
* aRequest
, const UsageRequestParams
& aParams
)
196 : PendingRequestInfo(aRequest
), mParams(aParams
) {
197 MOZ_ASSERT(aRequest
);
198 MOZ_ASSERT(aParams
.type() != UsageRequestParams::T__None
);
201 virtual nsresult
InitiateRequest(QuotaChild
* aActor
) override
;
204 class QuotaManagerService::RequestInfo
: public PendingRequestInfo
{
205 RequestParams mParams
;
208 RequestInfo(Request
* aRequest
, const RequestParams
& aParams
)
209 : PendingRequestInfo(aRequest
), mParams(aParams
) {
210 MOZ_ASSERT(aRequest
);
211 MOZ_ASSERT(aParams
.type() != RequestParams::T__None
);
214 virtual nsresult
InitiateRequest(QuotaChild
* aActor
) override
;
217 class QuotaManagerService::IdleMaintenanceInfo
: public PendingRequestInfo
{
221 explicit IdleMaintenanceInfo(bool aStart
)
222 : PendingRequestInfo(nullptr), mStart(aStart
) {}
224 virtual nsresult
InitiateRequest(QuotaChild
* aActor
) override
;
227 QuotaManagerService::QuotaManagerService()
228 : mBackgroundActor(nullptr),
229 mBackgroundActorFailed(false),
230 mIdleObserverRegistered(false) {
231 MOZ_ASSERT(NS_IsMainThread());
234 QuotaManagerService::~QuotaManagerService() {
235 MOZ_ASSERT(NS_IsMainThread());
236 MOZ_ASSERT(!mIdleObserverRegistered
);
240 QuotaManagerService
* QuotaManagerService::GetOrCreate() {
241 MOZ_ASSERT(NS_IsMainThread());
244 MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!");
248 if (!gQuotaManagerService
) {
249 RefPtr
<QuotaManagerService
> instance(new QuotaManagerService());
251 nsresult rv
= instance
->Init();
252 if (NS_WARN_IF(NS_FAILED(rv
))) {
256 if (gInitialized
.exchange(true)) {
257 MOZ_ASSERT(false, "Initialized more than once?!");
260 gQuotaManagerService
= instance
;
262 ClearOnShutdown(&gQuotaManagerService
);
265 return gQuotaManagerService
;
269 QuotaManagerService
* QuotaManagerService::Get() {
270 // Does not return an owning reference.
271 return gQuotaManagerService
;
275 already_AddRefed
<QuotaManagerService
> QuotaManagerService::FactoryCreate() {
276 RefPtr
<QuotaManagerService
> quotaManagerService
= GetOrCreate();
277 return quotaManagerService
.forget();
280 void QuotaManagerService::ClearBackgroundActor() {
281 MOZ_ASSERT(NS_IsMainThread());
283 mBackgroundActor
= nullptr;
286 void QuotaManagerService::AbortOperationsForProcess(
287 ContentParentId aContentParentId
) {
288 MOZ_ASSERT(XRE_IsParentProcess());
289 MOZ_ASSERT(NS_IsMainThread());
291 nsresult rv
= EnsureBackgroundActor();
292 if (NS_WARN_IF(NS_FAILED(rv
))) {
297 !mBackgroundActor
->SendAbortOperationsForProcess(aContentParentId
))) {
302 nsresult
QuotaManagerService::Init() {
303 MOZ_ASSERT(NS_IsMainThread());
305 if (XRE_IsParentProcess()) {
306 nsCOMPtr
<nsIObserverService
> observerService
=
307 mozilla::services::GetObserverService();
308 if (NS_WARN_IF(!observerService
)) {
309 return NS_ERROR_FAILURE
;
312 nsresult rv
= observerService
->AddObserver(
313 this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID
, false);
314 if (NS_WARN_IF(NS_FAILED(rv
))) {
322 void QuotaManagerService::Destroy() {
323 // Setting the closed flag prevents the service from being recreated.
324 // Don't set it though if there's no real instance created.
325 if (gInitialized
&& gClosed
.exchange(true)) {
326 MOZ_ASSERT(false, "Shutdown more than once?!");
332 nsresult
QuotaManagerService::EnsureBackgroundActor() {
333 MOZ_ASSERT(NS_IsMainThread());
335 // Nothing can be done here if we have previously failed to create a
337 if (mBackgroundActorFailed
) {
338 return NS_ERROR_FAILURE
;
341 if (!mBackgroundActor
) {
342 PBackgroundChild
* backgroundActor
=
343 BackgroundChild::GetOrCreateForCurrentThread();
344 if (NS_WARN_IF(!backgroundActor
)) {
345 mBackgroundActorFailed
= true;
346 return NS_ERROR_FAILURE
;
350 RefPtr
<QuotaChild
> actor
= new QuotaChild(this);
352 mBackgroundActor
= static_cast<QuotaChild
*>(
353 backgroundActor
->SendPQuotaConstructor(actor
));
357 if (!mBackgroundActor
) {
358 mBackgroundActorFailed
= true;
359 return NS_ERROR_FAILURE
;
365 nsresult
QuotaManagerService::InitiateRequest(PendingRequestInfo
& aInfo
) {
366 nsresult rv
= EnsureBackgroundActor();
367 if (NS_WARN_IF(NS_FAILED(rv
))) {
371 rv
= aInfo
.InitiateRequest(mBackgroundActor
);
372 if (NS_WARN_IF(NS_FAILED(rv
))) {
379 void QuotaManagerService::PerformIdleMaintenance() {
380 using namespace mozilla::hal
;
382 MOZ_ASSERT(XRE_IsParentProcess());
383 MOZ_ASSERT(NS_IsMainThread());
385 // If we're running on battery power then skip all idle maintenance since we
386 // would otherwise be doing lots of disk I/O.
387 BatteryInformation batteryInfo
;
389 #ifdef MOZ_WIDGET_ANDROID
390 // Android XPCShell doesn't load the AndroidBridge that is needed to make
391 // GetCurrentBatteryInformation work...
392 if (!QuotaManager::IsRunningXPCShellTests())
395 // In order to give the correct battery level, hal must have registered
396 // battery observers.
397 RegisterBatteryObserver(this);
398 GetCurrentBatteryInformation(&batteryInfo
);
399 UnregisterBatteryObserver(this);
402 // If we're running XPCShell because we always want to be able to test this
403 // code so pretend that we're always charging.
404 if (QuotaManager::IsRunningXPCShellTests()) {
405 batteryInfo
.level() = 100;
406 batteryInfo
.charging() = true;
409 if (NS_WARN_IF(!batteryInfo
.charging())) {
413 if (QuotaManager::IsRunningXPCShellTests()) {
414 // We don't want user activity to impact this code if we're running tests.
415 Unused
<< Observe(nullptr, OBSERVER_TOPIC_IDLE
, nullptr);
416 } else if (!mIdleObserverRegistered
) {
417 nsCOMPtr
<nsIUserIdleService
> idleService
=
418 do_GetService(kIdleServiceContractId
);
419 MOZ_ASSERT(idleService
);
422 idleService
->AddIdleObserver(this, kIdleObserverTimeSec
));
424 mIdleObserverRegistered
= true;
428 void QuotaManagerService::RemoveIdleObserver() {
429 MOZ_ASSERT(XRE_IsParentProcess());
430 MOZ_ASSERT(NS_IsMainThread());
432 if (mIdleObserverRegistered
) {
433 nsCOMPtr
<nsIUserIdleService
> idleService
=
434 do_GetService(kIdleServiceContractId
);
435 MOZ_ASSERT(idleService
);
437 // Ignore the return value of RemoveIdleObserver, it may fail if the
438 // observer has already been unregistered during shutdown.
439 Unused
<< idleService
->RemoveIdleObserver(this, kIdleObserverTimeSec
);
441 mIdleObserverRegistered
= false;
445 NS_IMPL_ADDREF(QuotaManagerService
)
446 NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService
, Destroy())
447 NS_IMPL_QUERY_INTERFACE(QuotaManagerService
, nsIQuotaManagerService
,
451 QuotaManagerService::StorageName(nsIQuotaRequest
** _retval
) {
452 MOZ_ASSERT(NS_IsMainThread());
453 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
455 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
456 return NS_ERROR_UNEXPECTED
;
459 RefPtr
<Request
> request
= new Request();
461 StorageNameParams params
;
463 RequestInfo
info(request
, params
);
465 nsresult rv
= InitiateRequest(info
);
466 if (NS_WARN_IF(NS_FAILED(rv
))) {
470 request
.forget(_retval
);
475 QuotaManagerService::StorageInitialized(nsIQuotaRequest
** _retval
) {
476 MOZ_ASSERT(NS_IsMainThread());
477 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
479 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
480 return NS_ERROR_UNEXPECTED
;
483 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
485 RefPtr
<Request
> request
= new Request();
487 mBackgroundActor
->SendStorageInitialized()->Then(
488 GetCurrentSerialEventTarget(), __func__
,
489 BoolResponsePromiseResolveOrRejectCallback(request
));
491 request
.forget(_retval
);
496 QuotaManagerService::TemporaryStorageInitialized(nsIQuotaRequest
** _retval
) {
497 MOZ_ASSERT(NS_IsMainThread());
498 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
500 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
501 return NS_ERROR_UNEXPECTED
;
504 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
506 RefPtr
<Request
> request
= new Request();
508 mBackgroundActor
->SendTemporaryStorageInitialized()->Then(
509 GetCurrentSerialEventTarget(), __func__
,
510 BoolResponsePromiseResolveOrRejectCallback(request
));
512 request
.forget(_retval
);
517 QuotaManagerService::Init(nsIQuotaRequest
** _retval
) {
518 MOZ_ASSERT(NS_IsMainThread());
519 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
521 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
522 return NS_ERROR_UNEXPECTED
;
525 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
527 RefPtr
<Request
> request
= new Request();
529 mBackgroundActor
->SendInitializeStorage()->Then(
530 GetCurrentSerialEventTarget(), __func__
,
531 BoolResponsePromiseResolveOrRejectCallback(request
));
533 request
.forget(_retval
);
538 QuotaManagerService::InitTemporaryStorage(nsIQuotaRequest
** _retval
) {
539 MOZ_ASSERT(NS_IsMainThread());
540 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
542 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
543 return NS_ERROR_UNEXPECTED
;
546 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
548 RefPtr
<Request
> request
= new Request();
550 mBackgroundActor
->SendInitializeTemporaryStorage()->Then(
551 GetCurrentSerialEventTarget(), __func__
,
552 BoolResponsePromiseResolveOrRejectCallback(request
));
554 request
.forget(_retval
);
559 QuotaManagerService::InitializePersistentOrigin(nsIPrincipal
* aPrincipal
,
560 nsIQuotaRequest
** _retval
) {
561 MOZ_ASSERT(NS_IsMainThread());
562 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
564 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
565 return NS_ERROR_UNEXPECTED
;
568 RefPtr
<Request
> request
= new Request();
570 InitializePersistentOriginParams params
;
573 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
574 if (NS_WARN_IF(NS_FAILED(rv
))) {
578 RequestInfo
info(request
, params
);
580 rv
= InitiateRequest(info
);
581 if (NS_WARN_IF(NS_FAILED(rv
))) {
585 request
.forget(_retval
);
590 QuotaManagerService::InitializeTemporaryOrigin(
591 const nsACString
& aPersistenceType
, nsIPrincipal
* aPrincipal
,
592 nsIQuotaRequest
** _retval
) {
593 MOZ_ASSERT(NS_IsMainThread());
594 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
596 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
597 return NS_ERROR_UNEXPECTED
;
600 RefPtr
<Request
> request
= new Request();
602 InitializeTemporaryOriginParams params
;
604 const auto maybePersistenceType
=
605 PersistenceTypeFromString(aPersistenceType
, fallible
);
606 if (NS_WARN_IF(maybePersistenceType
.isNothing())) {
607 return NS_ERROR_INVALID_ARG
;
610 if (NS_WARN_IF(!IsBestEffortPersistenceType(maybePersistenceType
.value()))) {
611 return NS_ERROR_FAILURE
;
614 params
.persistenceType() = maybePersistenceType
.value();
617 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
618 if (NS_WARN_IF(NS_FAILED(rv
))) {
622 RequestInfo
info(request
, params
);
624 rv
= InitiateRequest(info
);
625 if (NS_WARN_IF(NS_FAILED(rv
))) {
629 request
.forget(_retval
);
634 QuotaManagerService::InitializePersistentClient(nsIPrincipal
* aPrincipal
,
635 const nsAString
& aClientType
,
636 nsIQuotaRequest
** _retval
) {
637 MOZ_ASSERT(NS_IsMainThread());
638 MOZ_ASSERT(aPrincipal
);
639 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
641 QM_TRY(MOZ_TO_RESULT(StaticPrefs::dom_quotaManager_testing()),
642 NS_ERROR_UNEXPECTED
);
644 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
647 const auto& principalInfo
,
648 ([&aPrincipal
]() -> Result
<PrincipalInfo
, nsresult
> {
649 PrincipalInfo principalInfo
;
650 QM_TRY(MOZ_TO_RESULT(
651 PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)));
653 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo
)),
654 Err(NS_ERROR_INVALID_ARG
));
656 return principalInfo
;
659 QM_TRY_INSPECT(const auto& clientType
,
660 ([&aClientType
]() -> Result
<Client::Type
, nsresult
> {
661 Client::Type clientType
;
662 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
663 aClientType
, clientType
, fallible
)),
664 Err(NS_ERROR_INVALID_ARG
));
669 RefPtr
<Request
> request
= new Request();
671 mBackgroundActor
->SendInitializePersistentClient(principalInfo
, clientType
)
672 ->Then(GetCurrentSerialEventTarget(), __func__
,
673 BoolResponsePromiseResolveOrRejectCallback(request
));
675 request
.forget(_retval
);
680 QuotaManagerService::InitializeTemporaryClient(
681 const nsACString
& aPersistenceType
, nsIPrincipal
* aPrincipal
,
682 const nsAString
& aClientType
, nsIQuotaRequest
** _retval
) {
683 MOZ_ASSERT(NS_IsMainThread());
684 MOZ_ASSERT(aPrincipal
);
685 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
687 QM_TRY(MOZ_TO_RESULT(StaticPrefs::dom_quotaManager_testing()),
688 NS_ERROR_UNEXPECTED
);
690 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
693 const auto& persistenceType
,
694 ([&aPersistenceType
]() -> Result
<PersistenceType
, nsresult
> {
695 const auto persistenceType
=
696 PersistenceTypeFromString(aPersistenceType
, fallible
);
697 QM_TRY(MOZ_TO_RESULT(persistenceType
.isSome()),
698 Err(NS_ERROR_INVALID_ARG
));
701 MOZ_TO_RESULT(IsBestEffortPersistenceType(persistenceType
.ref())),
702 Err(NS_ERROR_INVALID_ARG
));
704 return persistenceType
.ref();
708 const auto& principalInfo
,
709 ([&aPrincipal
]() -> Result
<PrincipalInfo
, nsresult
> {
710 PrincipalInfo principalInfo
;
711 QM_TRY(MOZ_TO_RESULT(
712 PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)));
714 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo
)),
715 Err(NS_ERROR_INVALID_ARG
));
717 return principalInfo
;
720 QM_TRY_INSPECT(const auto& clientType
,
721 ([&aClientType
]() -> Result
<Client::Type
, nsresult
> {
722 Client::Type clientType
;
723 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
724 aClientType
, clientType
, fallible
)),
725 Err(NS_ERROR_INVALID_ARG
));
730 RefPtr
<Request
> request
= new Request();
733 ->SendInitializeTemporaryClient(persistenceType
, principalInfo
,
735 ->Then(GetCurrentSerialEventTarget(), __func__
,
736 BoolResponsePromiseResolveOrRejectCallback(request
));
738 request
.forget(_retval
);
743 QuotaManagerService::GetFullOriginMetadata(const nsACString
& aPersistenceType
,
744 nsIPrincipal
* aPrincipal
,
745 nsIQuotaRequest
** _retval
) {
746 MOZ_ASSERT(NS_IsMainThread());
747 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
749 QM_TRY(OkIf(StaticPrefs::dom_quotaManager_testing()), NS_ERROR_UNEXPECTED
);
751 const auto maybePersistenceType
=
752 PersistenceTypeFromString(aPersistenceType
, fallible
);
753 QM_TRY(OkIf(maybePersistenceType
.isSome()), NS_ERROR_INVALID_ARG
);
754 QM_TRY(OkIf(IsBestEffortPersistenceType(*maybePersistenceType
)),
755 NS_ERROR_INVALID_ARG
);
757 PrincipalInfo principalInfo
;
758 QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)));
759 QM_TRY(OkIf(QuotaManager::IsPrincipalInfoValid(principalInfo
)),
760 NS_ERROR_INVALID_ARG
);
762 RefPtr
<Request
> request
= new Request();
764 GetFullOriginMetadataParams params
;
766 params
.persistenceType() = *maybePersistenceType
;
767 params
.principalInfo() = std::move(principalInfo
);
769 RequestInfo
info(request
, params
);
771 QM_TRY(MOZ_TO_RESULT(InitiateRequest(info
)));
773 request
.forget(_retval
);
778 QuotaManagerService::GetUsage(nsIQuotaUsageCallback
* aCallback
, bool aGetAll
,
779 nsIQuotaUsageRequest
** _retval
) {
780 MOZ_ASSERT(NS_IsMainThread());
781 MOZ_ASSERT(aCallback
);
783 RefPtr
<UsageRequest
> request
= new UsageRequest(aCallback
);
785 AllUsageParams params
;
787 params
.getAll() = aGetAll
;
789 UsageRequestInfo
info(request
, params
);
791 nsresult rv
= InitiateRequest(info
);
792 if (NS_WARN_IF(NS_FAILED(rv
))) {
796 request
.forget(_retval
);
801 QuotaManagerService::GetUsageForPrincipal(nsIPrincipal
* aPrincipal
,
802 nsIQuotaUsageCallback
* aCallback
,
804 nsIQuotaUsageRequest
** _retval
) {
805 MOZ_ASSERT(NS_IsMainThread());
806 MOZ_ASSERT(aPrincipal
);
807 MOZ_ASSERT(aCallback
);
809 RefPtr
<UsageRequest
> request
= new UsageRequest(aPrincipal
, aCallback
);
811 OriginUsageParams params
;
814 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
815 if (NS_WARN_IF(NS_FAILED(rv
))) {
819 params
.fromMemory() = aFromMemory
;
821 UsageRequestInfo
info(request
, params
);
823 rv
= InitiateRequest(info
);
824 if (NS_WARN_IF(NS_FAILED(rv
))) {
828 request
.forget(_retval
);
833 QuotaManagerService::Clear(nsIQuotaRequest
** _retval
) {
834 MOZ_ASSERT(NS_IsMainThread());
836 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
837 return NS_ERROR_UNEXPECTED
;
840 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
842 RefPtr
<Request
> request
= new Request();
844 mBackgroundActor
->SendClearStorage()->Then(
845 GetCurrentSerialEventTarget(), __func__
,
846 BoolResponsePromiseResolveOrRejectCallback(request
));
848 request
.forget(_retval
);
853 QuotaManagerService::ClearStoragesForPrivateBrowsing(
854 nsIQuotaRequest
** _retval
) {
855 MOZ_ASSERT(NS_IsMainThread());
857 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
859 RefPtr
<Request
> request
= new Request();
861 mBackgroundActor
->SendClearStoragesForPrivateBrowsing()->Then(
862 GetCurrentSerialEventTarget(), __func__
,
863 BoolResponsePromiseResolveOrRejectCallback(request
));
865 request
.forget(_retval
);
870 QuotaManagerService::ClearStoragesForOriginAttributesPattern(
871 const nsAString
& aPattern
, nsIQuotaRequest
** _retval
) {
872 MOZ_ASSERT(NS_IsMainThread());
874 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
876 OriginAttributesPattern pattern
;
877 MOZ_ALWAYS_TRUE(pattern
.Init(aPattern
));
879 RefPtr
<Request
> request
= new Request();
881 mBackgroundActor
->SendClearStoragesForOriginAttributesPattern(pattern
)->Then(
882 GetCurrentSerialEventTarget(), __func__
,
883 BoolResponsePromiseResolveOrRejectCallback(request
));
885 request
.forget(_retval
);
890 QuotaManagerService::ClearStoragesForPrincipal(
891 nsIPrincipal
* aPrincipal
, const nsACString
& aPersistenceType
,
892 const nsAString
& aClientType
, nsIQuotaRequest
** _retval
) {
893 MOZ_ASSERT(NS_IsMainThread());
894 MOZ_ASSERT(aPrincipal
);
896 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
899 const auto& persistenceType
,
900 ([&aPersistenceType
]() -> Result
<Maybe
<PersistenceType
>, nsresult
> {
901 if (aPersistenceType
.IsVoid()) {
902 return Maybe
<PersistenceType
>();
905 const auto persistenceType
=
906 PersistenceTypeFromString(aPersistenceType
, fallible
);
907 QM_TRY(MOZ_TO_RESULT(persistenceType
.isSome()),
908 Err(NS_ERROR_INVALID_ARG
));
910 return persistenceType
;
914 const auto& principalInfo
,
915 ([&aPrincipal
]() -> Result
<PrincipalInfo
, nsresult
> {
916 PrincipalInfo principalInfo
;
917 QM_TRY(MOZ_TO_RESULT(
918 PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)));
920 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo
)),
921 Err(NS_ERROR_INVALID_ARG
));
923 return principalInfo
;
926 QM_TRY_INSPECT(const auto& clientType
,
927 ([&aClientType
]() -> Result
<Maybe
<Client::Type
>, nsresult
> {
928 if (aClientType
.IsVoid()) {
929 return Maybe
<Client::Type
>();
932 Client::Type clientType
;
933 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
934 aClientType
, clientType
, fallible
)),
935 Err(NS_ERROR_INVALID_ARG
));
937 return Some(clientType
);
940 RefPtr
<Request
> request
= new Request();
943 ->SendClearStoragesForOrigin(persistenceType
, principalInfo
, clientType
)
944 ->Then(GetCurrentSerialEventTarget(), __func__
,
945 BoolResponsePromiseResolveOrRejectCallback(request
));
947 request
.forget(_retval
);
952 QuotaManagerService::ClearStoragesForOriginPrefix(
953 nsIPrincipal
* aPrincipal
, const nsACString
& aPersistenceType
,
954 nsIQuotaRequest
** _retval
) {
955 MOZ_ASSERT(NS_IsMainThread());
956 MOZ_ASSERT(aPrincipal
);
958 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
961 const auto& persistenceType
,
962 ([&aPersistenceType
]() -> Result
<Maybe
<PersistenceType
>, nsresult
> {
963 if (aPersistenceType
.IsVoid()) {
964 return Maybe
<PersistenceType
>();
967 const auto persistenceType
=
968 PersistenceTypeFromString(aPersistenceType
, fallible
);
969 QM_TRY(MOZ_TO_RESULT(persistenceType
.isSome()),
970 Err(NS_ERROR_INVALID_ARG
));
972 return persistenceType
;
976 const auto& principalInfo
,
977 ([&aPrincipal
]() -> Result
<PrincipalInfo
, nsresult
> {
978 PrincipalInfo principalInfo
;
979 QM_TRY(MOZ_TO_RESULT(
980 PrincipalToPrincipalInfo(aPrincipal
, &principalInfo
)));
982 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo
)),
983 Err(NS_ERROR_INVALID_ARG
));
985 if (principalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
) {
987 principalInfo
.get_ContentPrincipalInfo().attrs().CreateSuffix(suffix
);
989 QM_TRY(MOZ_TO_RESULT(suffix
.IsEmpty()), Err(NS_ERROR_INVALID_ARG
));
992 return principalInfo
;
995 RefPtr
<Request
> request
= new Request();
998 ->SendClearStoragesForOriginPrefix(persistenceType
, principalInfo
)
999 ->Then(GetCurrentSerialEventTarget(), __func__
,
1000 BoolResponsePromiseResolveOrRejectCallback(request
));
1002 request
.forget(_retval
);
1007 QuotaManagerService::Reset(nsIQuotaRequest
** _retval
) {
1008 MOZ_ASSERT(NS_IsMainThread());
1010 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
1011 return NS_ERROR_UNEXPECTED
;
1014 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
1016 RefPtr
<Request
> request
= new Request();
1018 mBackgroundActor
->SendShutdownStorage()->Then(
1019 GetCurrentSerialEventTarget(), __func__
,
1020 BoolResponsePromiseResolveOrRejectCallback(request
));
1022 request
.forget(_retval
);
1027 QuotaManagerService::ResetStoragesForPrincipal(
1028 nsIPrincipal
* aPrincipal
, const nsACString
& aPersistenceType
,
1029 const nsAString
& aClientType
, nsIQuotaRequest
** _retval
) {
1030 MOZ_ASSERT(NS_IsMainThread());
1031 MOZ_ASSERT(aPrincipal
);
1033 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
1034 return NS_ERROR_UNEXPECTED
;
1037 RefPtr
<Request
> request
= new Request(aPrincipal
);
1039 ClearResetOriginParams commonParams
;
1041 nsresult rv
= GetClearResetOriginParams(aPrincipal
, aPersistenceType
,
1042 aClientType
, commonParams
);
1043 if (NS_WARN_IF(NS_FAILED(rv
))) {
1047 RequestParams params
;
1048 params
= ResetOriginParams(commonParams
);
1050 RequestInfo
info(request
, params
);
1052 rv
= InitiateRequest(info
);
1053 if (NS_WARN_IF(NS_FAILED(rv
))) {
1057 request
.forget(_retval
);
1062 QuotaManagerService::Persisted(nsIPrincipal
* aPrincipal
,
1063 nsIQuotaRequest
** _retval
) {
1064 MOZ_ASSERT(NS_IsMainThread());
1065 MOZ_ASSERT(aPrincipal
);
1066 MOZ_ASSERT(_retval
);
1068 RefPtr
<Request
> request
= new Request(aPrincipal
);
1070 PersistedParams params
;
1073 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
1074 if (NS_WARN_IF(NS_FAILED(rv
))) {
1078 RequestInfo
info(request
, params
);
1080 rv
= InitiateRequest(info
);
1081 if (NS_WARN_IF(NS_FAILED(rv
))) {
1085 request
.forget(_retval
);
1090 QuotaManagerService::Persist(nsIPrincipal
* aPrincipal
,
1091 nsIQuotaRequest
** _retval
) {
1092 MOZ_ASSERT(NS_IsMainThread());
1093 MOZ_ASSERT(aPrincipal
);
1094 MOZ_ASSERT(_retval
);
1096 RefPtr
<Request
> request
= new Request(aPrincipal
);
1098 PersistParams params
;
1101 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
1102 if (NS_WARN_IF(NS_FAILED(rv
))) {
1106 RequestInfo
info(request
, params
);
1108 rv
= InitiateRequest(info
);
1109 if (NS_WARN_IF(NS_FAILED(rv
))) {
1113 request
.forget(_retval
);
1118 QuotaManagerService::Estimate(nsIPrincipal
* aPrincipal
,
1119 nsIQuotaRequest
** _retval
) {
1120 MOZ_ASSERT(NS_IsMainThread());
1121 MOZ_ASSERT(aPrincipal
);
1123 RefPtr
<Request
> request
= new Request(aPrincipal
);
1125 EstimateParams params
;
1128 CheckedPrincipalToPrincipalInfo(aPrincipal
, params
.principalInfo());
1129 if (NS_WARN_IF(NS_FAILED(rv
))) {
1133 RequestInfo
info(request
, params
);
1135 rv
= InitiateRequest(info
);
1136 if (NS_WARN_IF(NS_FAILED(rv
))) {
1140 request
.forget(_retval
);
1145 QuotaManagerService::ListOrigins(nsIQuotaRequest
** _retval
) {
1146 MOZ_ASSERT(NS_IsMainThread());
1148 RefPtr
<Request
> request
= new Request();
1150 ListOriginsParams params
;
1152 RequestInfo
info(request
, params
);
1154 nsresult rv
= InitiateRequest(info
);
1155 if (NS_WARN_IF(NS_FAILED(rv
))) {
1159 request
.forget(_retval
);
1164 QuotaManagerService::Observe(nsISupports
* aSubject
, const char* aTopic
,
1165 const char16_t
* aData
) {
1166 MOZ_ASSERT(XRE_IsParentProcess());
1167 MOZ_ASSERT(NS_IsMainThread());
1169 if (!strcmp(aTopic
, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID
)) {
1170 RemoveIdleObserver();
1174 if (!strcmp(aTopic
, OBSERVER_TOPIC_IDLE_DAILY
)) {
1175 PerformIdleMaintenance();
1179 if (!strcmp(aTopic
, OBSERVER_TOPIC_IDLE
)) {
1180 IdleMaintenanceInfo
info(/* aStart */ true);
1182 nsresult rv
= InitiateRequest(info
);
1183 if (NS_WARN_IF(NS_FAILED(rv
))) {
1190 if (!strcmp(aTopic
, OBSERVER_TOPIC_ACTIVE
)) {
1191 RemoveIdleObserver();
1193 IdleMaintenanceInfo
info(/* aStart */ false);
1195 nsresult rv
= InitiateRequest(info
);
1196 if (NS_WARN_IF(NS_FAILED(rv
))) {
1203 MOZ_ASSERT_UNREACHABLE("Should never get here!");
1207 void QuotaManagerService::Notify(const hal::BatteryInformation
& aBatteryInfo
) {
1208 // This notification is received when battery data changes. We don't need to
1209 // deal with this notification.
1212 nsresult
QuotaManagerService::UsageRequestInfo::InitiateRequest(
1213 QuotaChild
* aActor
) {
1216 auto request
= static_cast<UsageRequest
*>(mRequest
.get());
1218 auto actor
= new QuotaUsageRequestChild(request
);
1220 if (!aActor
->SendPQuotaUsageRequestConstructor(actor
, mParams
)) {
1221 request
->SetError(NS_ERROR_FAILURE
);
1222 return NS_ERROR_FAILURE
;
1225 request
->SetBackgroundActor(actor
);
1230 nsresult
QuotaManagerService::RequestInfo::InitiateRequest(QuotaChild
* aActor
) {
1233 auto request
= static_cast<Request
*>(mRequest
.get());
1235 auto actor
= new QuotaRequestChild(request
);
1237 if (!aActor
->SendPQuotaRequestConstructor(actor
, mParams
)) {
1238 request
->SetError(NS_ERROR_FAILURE
);
1239 return NS_ERROR_FAILURE
;
1245 nsresult
QuotaManagerService::IdleMaintenanceInfo::InitiateRequest(
1246 QuotaChild
* aActor
) {
1252 result
= aActor
->SendStartIdleMaintenance();
1254 result
= aActor
->SendStopIdleMaintenance();
1258 return NS_ERROR_FAILURE
;
1264 } // namespace mozilla::dom::quota