diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index 50e428d0bebf..d5b35dfffd47 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -145,7 +145,9 @@ QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse) AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - mRequest->SetResult(aResponse.usage(), aResponse.fileUsage()); + mRequest->SetResult(aResponse.usage(), + aResponse.fileUsage(), + aResponse.limit()); } void diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index a1f96ab96b96..1af3d676fba6 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1008,11 +1008,16 @@ class GetUsageOp final : public NormalOriginOperationBase , public PQuotaUsageRequestParent { + // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage + // and the file usage. Otherwise, we use it to record the group usage and the + // limit. UsageInfo mUsageInfo; const UsageParams mParams; + nsCString mSuffix; nsCString mGroup; bool mIsApp; + bool mGetGroupUsage; public: explicit GetUsageOp(const UsageRequestParams& aParams); @@ -4583,6 +4588,40 @@ QuotaManager::GetGroupLimit() const std::max(x, 10 MB)); } +void +QuotaManager::GetGroupUsageAndLimit(const nsACString& aGroup, + UsageInfo* aUsageInfo) +{ + AssertIsOnIOThread(); + MOZ_ASSERT(aUsageInfo); + + { + MutexAutoLock lock(mQuotaMutex); + + aUsageInfo->SetLimit(GetGroupLimit()); + aUsageInfo->ResetUsage(); + + GroupInfoPair* pair; + if (!mGroupInfoPairs.Get(aGroup, &pair)) { + return; + } + + // Calculate temporary group usage + RefPtr temporaryGroupInfo = + pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY); + if (temporaryGroupInfo) { + aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage); + } + + // Calculate default group usage + RefPtr defaultGroupInfo = + pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT); + if (defaultGroupInfo) { + aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage); + } + } +} + // static void QuotaManager::GetStorageId(PersistenceType aPersistenceType, @@ -5845,6 +5884,7 @@ GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) OriginScope::FromNull(), /* aExclusive */ false) , mParams(aParams.get_UsageParams()) + , mGetGroupUsage(aParams.get_UsageParams().getGroupUsage()) { AssertIsOnOwningThread(); MOZ_ASSERT(aParams.type() == UsageRequestParams::TUsageParams); @@ -5880,7 +5920,7 @@ GetUsageOp::DoInitOnMainThread() // Figure out which origin we're dealing with. nsCString origin; - rv = QuotaManager::GetInfoFromPrincipal(principal, nullptr, &mGroup, &origin, + rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, &origin, &mIsApp); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -5995,12 +6035,34 @@ nsresult GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { AssertIsOnIOThread(); + MOZ_ASSERT(mUsageInfo.TotalUsage() == 0); PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork", js::ProfileEntry::Category::OTHER); - // Add all the persistent/temporary/default storage files we care about. nsresult rv; + + if (mGetGroupUsage) { + nsCOMPtr directory; + + // Ensure origin is initialized first. It will initialize all origins for + // temporary storage including origins belonging to our group. + rv = aQuotaManager->EnsureOriginIsInitialized(PERSISTENCE_TYPE_TEMPORARY, + mSuffix, mGroup, + mOriginScope.GetOrigin(), + mIsApp, + getter_AddRefs(directory)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Get cached usage and limit (the method doesn't have to stat any files). + aQuotaManager->GetGroupUsageAndLimit(mGroup, &mUsageInfo); + + return NS_OK; + } + + // Add all the persistent/temporary/default storage files we care about. for (const PersistenceType type : kAllPersistenceTypes) { rv = AddToUsage(aQuotaManager, type); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -6029,8 +6091,17 @@ GetUsageOp::SendResults() if (NS_SUCCEEDED(mResultCode)) { UsageResponse usageResponse; + + // We'll get the group usage when mGetGroupUsage is true and get the + // origin usage when mGetGroupUsage is false. usageResponse.usage() = mUsageInfo.TotalUsage(); - usageResponse.fileUsage() = mUsageInfo.FileUsage(); + + if (mGetGroupUsage) { + usageResponse.limit() = mUsageInfo.Limit(); + } else { + usageResponse.fileUsage() = mUsageInfo.FileUsage(); + } + response = usageResponse; } else { response = mResultCode; diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl index cd6f669ae12c..5e41794b8f33 100644 --- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -20,6 +20,7 @@ namespace quota { struct UsageParams { PrincipalInfo principalInfo; + bool getGroupUsage; }; union UsageRequestParams diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl index a132e0d0dac5..fbf7941c15d1 100644 --- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -12,6 +12,7 @@ struct UsageResponse { uint64_t usage; uint64_t fileUsage; + uint64_t limit; }; union UsageRequestResponse diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h index 743197270f67..00571ff8c7bc 100644 --- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -347,6 +347,10 @@ public: uint64_t GetGroupLimit() const; + void + GetGroupUsageAndLimit(const nsACString& aGroup, + UsageInfo* aUsageInfo); + static void GetStorageId(PersistenceType aPersistenceType, const nsACString& aOrigin, diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index 4acf681e38f2..4148ce7f383e 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -497,6 +497,7 @@ NS_IMPL_QUERY_INTERFACE(QuotaManagerService, NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, + bool aGetGroupUsage, nsIQuotaUsageRequest** _retval) { MOZ_ASSERT(NS_IsMainThread()); @@ -509,7 +510,6 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, UsageParams params; PrincipalInfo& principalInfo = params.principalInfo(); - nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -520,6 +520,8 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, return NS_ERROR_UNEXPECTED; } + params.getGroupUsage() = aGetGroupUsage; + nsAutoPtr info(new UsageRequestInfo(request, params)); rv = InitiateRequest(info); diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp index 776d541b058f..15fa90fe9c3a 100644 --- a/dom/quota/QuotaRequests.cpp +++ b/dom/quota/QuotaRequests.cpp @@ -92,11 +92,12 @@ RequestBase::GetResultCode(nsresult* aResultCode) } UsageRequest::UsageRequest(nsIPrincipal* aPrincipal, - nsIQuotaUsageCallback* aCallback) + nsIQuotaUsageCallback* aCallback) : RequestBase(aPrincipal) , mCallback(aCallback) , mUsage(0) , mFileUsage(0) + , mLimit(0) , mBackgroundActor(nullptr) , mCanceled(false) { @@ -125,13 +126,14 @@ UsageRequest::SetBackgroundActor(QuotaUsageRequestChild* aBackgroundActor) } void -UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage) +UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit) { AssertIsOnOwningThread(); MOZ_ASSERT(!mHaveResultOrErrorCode); mUsage = aUsage; mFileUsage = aFileUsage; + mLimit = aLimit; mHaveResultOrErrorCode = true; FireCallback(); @@ -173,6 +175,20 @@ UsageRequest::GetFileUsage(uint64_t* aFileUsage) return NS_OK; } +NS_IMETHODIMP +UsageRequest::GetLimit(uint64_t* aLimit) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aLimit); + + if (!mHaveResultOrErrorCode) { + return NS_ERROR_FAILURE; + } + + *aLimit = mLimit; + return NS_OK; +} + NS_IMETHODIMP UsageRequest::GetCallback(nsIQuotaUsageCallback** aCallback) { diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h index aeeca73f4d35..f989f84b6652 100644 --- a/dom/quota/QuotaRequests.h +++ b/dom/quota/QuotaRequests.h @@ -74,6 +74,9 @@ class UsageRequest final uint64_t mUsage; uint64_t mFileUsage; + // Group Limit. + uint64_t mLimit; + QuotaUsageRequestChild* mBackgroundActor; bool mCanceled; @@ -94,7 +97,7 @@ public: } void - SetResult(uint64_t aUsage, uint64_t aFileUsage); + SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIQUOTAREQUESTBASE(RequestBase::) diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h index aa6b6e53c3db..688e168707fa 100644 --- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -18,7 +18,7 @@ class UsageInfo { public: UsageInfo() - : mCanceled(false), mDatabaseUsage(0), mFileUsage(0) + : mCanceled(false), mDatabaseUsage(0), mFileUsage(0), mLimit(0) { } virtual ~UsageInfo() @@ -52,6 +52,12 @@ public: IncrementUsage(&mFileUsage, aUsage); } + void + SetLimit(uint64_t aLimit) + { + mLimit = aLimit; + } + uint64_t DatabaseUsage() { @@ -64,6 +70,12 @@ public: return mFileUsage; } + uint64_t + Limit() + { + return mLimit; + } + uint64_t TotalUsage() { @@ -98,6 +110,7 @@ protected: private: uint64_t mDatabaseUsage; uint64_t mFileUsage; + uint64_t mLimit; }; END_QUOTA_NAMESPACE diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl index 763e25a89e8e..2f2b427413c7 100644 --- a/dom/quota/nsIQuotaManagerService.idl +++ b/dom/quota/nsIQuotaManagerService.idl @@ -22,10 +22,16 @@ interface nsIQuotaManagerService : nsISupports * A principal for the origin whose usage is being queried. * @param aCallback * The callback that will be called when the usage is available. + * @param aGetGroupUsage + * An optional flag to indicate whether getting group usage and limit + * or origin usage and file usage. The default value is false. + * Note: Origin usage here represents total usage of an origin. However, + * group usage here represents only non-persistent usage of a group. */ nsIQuotaUsageRequest getUsageForPrincipal(in nsIPrincipal aPrincipal, - in nsIQuotaUsageCallback aCallback); + in nsIQuotaUsageCallback aCallback, + [optional] in boolean aGetGroupUsage); /** * Removes all storages. The files may not be deleted immediately depending diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl index 7252045672ff..1eab5bca4693 100644 --- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -25,6 +25,8 @@ interface nsIQuotaUsageRequest : nsIQuotaRequestBase readonly attribute unsigned long long fileUsage; + readonly attribute unsigned long long limit; + attribute nsIQuotaUsageCallback callback; void