gecko-dev/dom/storage/StorageIPC.cpp
Nika Layzell 852d02ec16 Bug 1809753 - Part 3: Replace all callers of GetCurrentEventTarget with GetCurrentSerialEventTarget, r=mccr8,necko-reviewers,valentin
This only changes the behaviour when called with a TaskQueue or other type
using SerialEventTargetGuard on the stack. They are being switched over as the
existing GetCurrentEventTarget method is being removed, as it is somewhat
confusing, and poorly documented.

Callers which need to get the current thread even when on a threadpool or
behind a TaskQueue were switched to GetCurrentEventTarget in the previous part.

Differential Revision: https://phabricator.services.mozilla.com/D166607
2023-01-16 23:14:11 +00:00

1599 lines
46 KiB
C++

/* -*- 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 "StorageIPC.h"
#include "StorageCommon.h"
#include "StorageUtils.h"
#include "LocalStorageManager.h"
#include "SessionStorageObserver.h"
#include "SessionStorageManager.h"
#include "SessionStorageCache.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/PBackgroundParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsIPrincipal.h"
#include "nsThreadUtils.h"
namespace mozilla::dom {
namespace {
using LocalStorageCacheParentHashtable =
nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>;
StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents;
StorageDBChild* sStorageChild[kPrivateBrowsingIdCount] = {nullptr, nullptr};
// False until we shut the storage child down.
bool sStorageChildDown[kPrivateBrowsingIdCount] = {false, false};
} // namespace
LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache)
: mCache(aCache) {
AssertIsOnOwningThread();
MOZ_ASSERT(aCache);
aCache->AssertIsOnOwningThread();
MOZ_COUNT_CTOR(LocalStorageCacheChild);
}
LocalStorageCacheChild::~LocalStorageCacheChild() {
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(LocalStorageCacheChild);
}
void LocalStorageCacheChild::SendDeleteMeInternal() {
AssertIsOnOwningThread();
if (mCache) {
mCache->ClearActor();
mCache = nullptr;
MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe());
}
}
void LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
if (mCache) {
mCache->ClearActor();
mCache = nullptr;
}
}
mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve(
const PrincipalInfo& aPrincipalInfo,
const PrincipalInfo& aCachePrincipalInfo,
const uint32_t& aPrivateBrowsingId, const nsAString& aDocumentURI,
const nsAString& aKey, const nsAString& aOldValue,
const nsAString& aNewValue) {
AssertIsOnOwningThread();
auto principalOrErr = PrincipalInfoToPrincipal(aPrincipalInfo);
if (NS_WARN_IF(principalOrErr.isErr())) {
return IPC_FAIL_NO_REASON(this);
}
auto cachePrincipalOrErr = PrincipalInfoToPrincipal(aCachePrincipalInfo);
if (NS_WARN_IF(cachePrincipalOrErr.isErr())) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
nsCOMPtr<nsIPrincipal> cachePrincipal = cachePrincipalOrErr.unwrap();
if (StorageUtils::PrincipalsEqual(principal, cachePrincipal)) {
Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
aNewValue,
/* aStorageType */ u"localStorage", aDocumentURI,
/* aIsPrivate */ !!aPrivateBrowsingId,
/* aImmediateDispatch */ true);
}
return IPC_OK();
}
// ----------------------------------------------------------------------------
// Child
// ----------------------------------------------------------------------------
class StorageDBChild::ShutdownObserver final : public nsIObserver {
// Expected to be only 0 or 1.
const uint32_t mPrivateBrowsingId;
public:
explicit ShutdownObserver(const uint32_t aPrivateBrowsingId)
: mPrivateBrowsingId(aPrivateBrowsingId) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
};
void StorageDBChild::AddIPDLReference() {
MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
mIPCOpen = true;
AddRef();
}
void StorageDBChild::ReleaseIPDLReference() {
MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
mIPCOpen = false;
Release();
}
StorageDBChild::StorageDBChild(LocalStorageManager* aManager,
const uint32_t aPrivateBrowsingId)
: mManager(aManager),
mPrivateBrowsingId(aPrivateBrowsingId),
mStatus(NS_OK),
mIPCOpen(false) {
MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
MOZ_ASSERT(!NextGenLocalStorageEnabled());
}
StorageDBChild::~StorageDBChild() = default;
// static
StorageDBChild* StorageDBChild::Get(const uint32_t aPrivateBrowsingId) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
MOZ_ASSERT(!NextGenLocalStorageEnabled());
return sStorageChild[aPrivateBrowsingId];
}
// static
StorageDBChild* StorageDBChild::GetOrCreate(const uint32_t aPrivateBrowsingId) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
MOZ_ASSERT(!NextGenLocalStorageEnabled());
StorageDBChild*& storageChild = sStorageChild[aPrivateBrowsingId];
if (storageChild || sStorageChildDown[aPrivateBrowsingId]) {
// When sStorageChildDown is at true, sStorageChild is null.
// Checking sStorageChildDown flag here prevents reinitialization of
// the storage child after shutdown.
return storageChild;
}
// Use LocalStorageManager::Ensure in case we're called from
// DOMSessionStorageManager's initializer and we haven't yet initialized the
// local storage manager.
RefPtr<StorageDBChild> newStorageChild =
new StorageDBChild(LocalStorageManager::Ensure(), aPrivateBrowsingId);
nsresult rv = newStorageChild->Init();
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
newStorageChild.forget(&storageChild);
return storageChild;
}
nsTHashSet<nsCString>& StorageDBChild::OriginsHavingData() {
if (!mOriginsHavingData) {
mOriginsHavingData = MakeUnique<nsTHashSet<nsCString>>();
}
return *mOriginsHavingData;
}
nsresult StorageDBChild::Init() {
MOZ_ASSERT(NS_IsMainThread());
::mozilla::ipc::PBackgroundChild* actor =
::mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!actor)) {
return NS_ERROR_FAILURE;
}
nsString profilePath;
if (XRE_IsParentProcess() && mPrivateBrowsingId == 0) {
nsresult rv = StorageDBThread::GetProfilePath(profilePath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
AddIPDLReference();
actor->SendPBackgroundStorageConstructor(this, profilePath,
mPrivateBrowsingId);
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
MOZ_ASSERT(observerService);
nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mPrivateBrowsingId);
MOZ_ALWAYS_SUCCEEDS(
observerService->AddObserver(observer, "xpcom-shutdown", false));
return NS_OK;
}
nsresult StorageDBChild::Shutdown() {
// There is nothing to do here, IPC will release automatically and
// the actual thread running on the parent process will also stop
// automatically in profile-before-change topic observer.
return NS_OK;
}
void StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache,
bool aPriority) {
if (mIPCOpen) {
// Adding ref to cache for the time of preload. This ensures a reference to
// to the cache and that all keys will load into this cache object.
mLoadingCaches.Insert(aCache);
SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
aPriority);
} else {
// No IPC, no love. But the LoadDone call is expected.
aCache->LoadDone(NS_ERROR_UNEXPECTED);
}
}
void StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage) {
if (mIPCOpen) {
SendAsyncGetUsage(aUsage->OriginScope());
}
}
void StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache,
bool aForceSync) {
if (NS_FAILED(mStatus)) {
aCache->LoadDone(mStatus);
return;
}
if (!mIPCOpen) {
aCache->LoadDone(NS_ERROR_UNEXPECTED);
return;
}
// There is no way to put the child process to a wait state to receive all
// incoming async responses from the parent, hence we have to do a sync
// preload instead. We are smart though, we only demand keys that are left to
// load in case the async preload has already loaded some keys.
nsTArray<nsString> keys, values;
nsresult rv;
SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
aCache->LoadedCount(), &keys, &values, &rv);
for (uint32_t i = 0; i < keys.Length(); ++i) {
aCache->LoadItem(keys[i], values[i]);
}
aCache->LoadDone(rv);
}
nsresult StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache,
const nsAString& aKey,
const nsAString& aValue) {
if (NS_FAILED(mStatus) || !mIPCOpen) {
return mStatus;
}
SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
nsString(aKey), nsString(aValue));
OriginsHavingData().Insert(aCache->Origin());
return NS_OK;
}
nsresult StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache,
const nsAString& aKey,
const nsAString& aValue) {
if (NS_FAILED(mStatus) || !mIPCOpen) {
return mStatus;
}
SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
nsString(aKey), nsString(aValue));
OriginsHavingData().Insert(aCache->Origin());
return NS_OK;
}
nsresult StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache,
const nsAString& aKey) {
if (NS_FAILED(mStatus) || !mIPCOpen) {
return mStatus;
}
SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
nsString(aKey));
return NS_OK;
}
nsresult StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache) {
if (NS_FAILED(mStatus) || !mIPCOpen) {
return mStatus;
}
SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
OriginsHavingData().Remove(aCache->Origin());
return NS_OK;
}
bool StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin) {
// Return true if we didn't receive the origins list yet.
// I tend to rather preserve a bit of early-after-start performance
// than a bit of memory here.
return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
}
mozilla::ipc::IPCResult StorageDBChild::RecvObserve(
const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
MOZ_ASSERT(!XRE_IsParentProcess());
if (StorageObserver* obs = StorageObserver::Self()) {
obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
aOriginScope);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBChild::RecvOriginsHavingData(
nsTArray<nsCString>&& aOrigins) {
// Force population of mOriginsHavingData even if there are no origins so that
// ShouldPreloadOrigin does not generate false positives for all origins.
if (!aOrigins.Length()) {
Unused << OriginsHavingData();
}
for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
OriginsHavingData().Insert(aOrigins[i]);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBChild::RecvLoadItem(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const nsAString& aKey, const nsAString& aValue) {
LocalStorageCache* aCache =
mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
if (aCache) {
aCache->LoadItem(aKey, aValue);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const nsresult& aRv) {
LocalStorageCache* aCache =
mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
if (aCache) {
aCache->LoadDone(aRv);
// Just drop reference to this cache now since the load is done.
mLoadingCaches.Remove(static_cast<LocalStorageCacheBridge*>(aCache));
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage(
const nsACString& aOriginNoSuffix, const int64_t& aUsage) {
RefPtr<StorageUsageBridge> scopeUsage =
mManager->GetOriginUsage(aOriginNoSuffix, mPrivateBrowsingId);
scopeUsage->LoadUsage(aUsage);
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) {
mStatus = aRv;
return IPC_OK();
}
NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
NS_IMETHODIMP
StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (NS_WARN_IF(!observerService)) {
return NS_ERROR_FAILURE;
}
Unused << observerService->RemoveObserver(this, "xpcom-shutdown");
StorageDBChild*& storageChild = sStorageChild[mPrivateBrowsingId];
if (storageChild) {
sStorageChildDown[mPrivateBrowsingId] = true;
MOZ_ALWAYS_TRUE(storageChild->PBackgroundStorageChild::SendDeleteMe());
NS_RELEASE(storageChild);
storageChild = nullptr;
}
return NS_OK;
}
SessionStorageObserverChild::SessionStorageObserverChild(
SessionStorageObserver* aObserver)
: mObserver(aObserver) {
AssertIsOnOwningThread();
MOZ_ASSERT(NextGenLocalStorageEnabled());
MOZ_ASSERT(aObserver);
aObserver->AssertIsOnOwningThread();
MOZ_COUNT_CTOR(SessionStorageObserverChild);
}
SessionStorageObserverChild::~SessionStorageObserverChild() {
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(SessionStorageObserverChild);
}
void SessionStorageObserverChild::SendDeleteMeInternal() {
AssertIsOnOwningThread();
if (mObserver) {
mObserver->ClearActor();
mObserver = nullptr;
// Don't check result here since IPC may no longer be available due to
// SessionStorageManager (which holds a strong reference to
// SessionStorageObserver) being destroyed very late in the game.
PSessionStorageObserverChild::SendDeleteMe();
}
}
void SessionStorageObserverChild::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
if (mObserver) {
mObserver->ClearActor();
mObserver = nullptr;
}
}
mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
AssertIsOnOwningThread();
if (StorageObserver* obs = StorageObserver::Self()) {
obs->Notify(PromiseFlatCString(aTopic).get(), aOriginAttributesPattern,
aOriginScope);
}
return IPC_OK();
}
SessionStorageCacheChild::SessionStorageCacheChild(SessionStorageCache* aCache)
: mCache(aCache) {
AssertIsOnOwningThread();
MOZ_ASSERT(mCache);
MOZ_COUNT_CTOR(SessionStorageCacheChild);
}
SessionStorageCacheChild::~SessionStorageCacheChild() {
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(SessionStorageCacheChild);
}
void SessionStorageCacheChild::SendDeleteMeInternal() {
AssertIsOnOwningThread();
if (mCache) {
mCache->ClearActor();
mCache = nullptr;
MOZ_ALWAYS_TRUE(PBackgroundSessionStorageCacheChild::SendDeleteMe());
}
}
void SessionStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
if (mCache) {
mCache->ClearActor();
mCache = nullptr;
}
}
SessionStorageManagerChild::SessionStorageManagerChild(
SessionStorageManager* aSSManager)
: mSSManager(aSSManager) {
AssertIsOnOwningThread();
MOZ_ASSERT(mSSManager);
MOZ_COUNT_CTOR(SessionStorageManagerChild);
}
SessionStorageManagerChild::~SessionStorageManagerChild() {
AssertIsOnOwningThread();
MOZ_COUNT_DTOR(SessionStorageManagerChild);
}
void SessionStorageManagerChild::SendDeleteMeInternal() {
AssertIsOnOwningThread();
if (mSSManager) {
mSSManager->ClearActor();
mSSManager = nullptr;
MOZ_ALWAYS_TRUE(PBackgroundSessionStorageManagerChild::SendDeleteMe());
}
}
void SessionStorageManagerChild::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnOwningThread();
if (mSSManager) {
mSSManager->ClearActor();
mSSManager = nullptr;
}
}
mozilla::ipc::IPCResult SessionStorageManagerChild::RecvClearStoragesForOrigin(
const nsACString& aOriginAttrs, const nsACString& aOriginKey) {
AssertIsOnOwningThread();
if (mSSManager) {
mSSManager->ClearStoragesForOrigin(aOriginAttrs, aOriginKey);
}
return IPC_OK();
}
LocalStorageCacheParent::LocalStorageCacheParent(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
: mPrincipalInfo(aPrincipalInfo),
mOriginKey(aOriginKey),
mPrivateBrowsingId(aPrivateBrowsingId),
mActorDestroyed(false) {
::mozilla::ipc::AssertIsOnBackgroundThread();
}
LocalStorageCacheParent::~LocalStorageCacheParent() {
MOZ_ASSERT(mActorDestroyed);
}
void LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
mActorDestroyed = true;
MOZ_ASSERT(gLocalStorageCacheParents);
nsTArray<LocalStorageCacheParent*>* array;
gLocalStorageCacheParents->Get(mOriginKey, &array);
MOZ_ASSERT(array);
array->RemoveElement(this);
if (array->IsEmpty()) {
gLocalStorageCacheParents->Remove(mOriginKey);
}
if (!gLocalStorageCacheParents->Count()) {
gLocalStorageCacheParents = nullptr;
}
}
mozilla::ipc::IPCResult LocalStorageCacheParent::RecvDeleteMe() {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
mozilla::ipc::IPCResult LocalStorageCacheParent::RecvNotify(
const nsAString& aDocumentURI, const nsAString& aKey,
const nsAString& aOldValue, const nsAString& aNewValue) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(gLocalStorageCacheParents);
nsTArray<LocalStorageCacheParent*>* array;
gLocalStorageCacheParents->Get(mOriginKey, &array);
MOZ_ASSERT(array);
for (LocalStorageCacheParent* localStorageCacheParent : *array) {
if (localStorageCacheParent != this) {
// When bug 1443925 is fixed, we can compare mPrincipalInfo against
// localStorageCacheParent->PrincipalInfo() here on the background thread
// instead of posting it to the main thread. The advantage of doing so is
// that it would save an IPC message in the case where the principals do
// not match.
Unused << localStorageCacheParent->SendObserve(
mPrincipalInfo, localStorageCacheParent->PrincipalInfo(),
mPrivateBrowsingId, aDocumentURI, aKey, aOldValue, aNewValue);
}
}
return IPC_OK();
}
// ----------------------------------------------------------------------------
// Parent
// ----------------------------------------------------------------------------
class StorageDBParent::ObserverSink : public StorageObserverSink {
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
// Only touched on the PBackground thread.
StorageDBParent* MOZ_NON_OWNING_REF mActor;
public:
explicit ObserverSink(StorageDBParent* aActor)
: mOwningEventTarget(GetCurrentSerialEventTarget()), mActor(aActor) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink);
void Start();
void Stop();
private:
~ObserverSink() = default;
void AddSink();
void RemoveSink();
void Notify(const nsACString& aTopic,
const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope);
// StorageObserverSink
nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern,
const nsACString& aOriginScope) override;
};
NS_IMPL_ADDREF(StorageDBParent)
NS_IMPL_RELEASE(StorageDBParent)
void StorageDBParent::AddIPDLReference() {
MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
mIPCOpen = true;
AddRef();
}
void StorageDBParent::ReleaseIPDLReference() {
MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
mIPCOpen = false;
Release();
}
namespace {} // namespace
StorageDBParent::StorageDBParent(const nsAString& aProfilePath,
const uint32_t aPrivateBrowsingId)
: mProfilePath(aProfilePath),
mPrivateBrowsingId(aPrivateBrowsingId),
mIPCOpen(false) {
::mozilla::ipc::AssertIsOnBackgroundThread();
// We are always open by IPC only
AddIPDLReference();
}
StorageDBParent::~StorageDBParent() {
::mozilla::ipc::AssertIsOnBackgroundThread();
if (mObserverSink) {
mObserverSink->Stop();
mObserverSink = nullptr;
}
}
void StorageDBParent::Init() {
::mozilla::ipc::AssertIsOnBackgroundThread();
PBackgroundParent* actor = Manager();
MOZ_ASSERT(actor);
if (::mozilla::ipc::BackgroundParent::IsOtherProcessActor(actor)) {
mObserverSink = new ObserverSink(this);
mObserverSink->Start();
}
StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
if (storageThread) {
nsTArray<nsCString> scopes;
storageThread->GetOriginsHavingData(&scopes);
mozilla::Unused << SendOriginsHavingData(scopes);
}
}
StorageDBParent::CacheParentBridge* StorageDBParent::NewCache(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
}
void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) {
// Implement me! Bug 1005169
}
mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
::mozilla::ipc::AssertIsOnBackgroundThread();
IProtocol* mgr = Manager();
if (!PBackgroundStorageParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const bool& aPriority) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
aPriority);
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage(
const nsACString& aOriginNoSuffix) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
// The object releases it self in LoadUsage method
RefPtr<UsageParentBridge> usage =
new UsageParentBridge(this, aOriginNoSuffix);
storageThread->AsyncGetUsage(usage);
return IPC_OK();
}
namespace {
// We need another implementation of LocalStorageCacheBridge to do
// synchronous IPC preload. This class just receives Load* notifications
// and fills the returning arguments of RecvPreload with the database
// values for us.
class SyncLoadCacheHelper : public LocalStorageCacheBridge {
public:
SyncLoadCacheHelper(const nsACString& aOriginSuffix,
const nsACString& aOriginNoSuffix,
uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
nsTArray<nsString>* aValues, nsresult* rv)
: mMonitor("DOM Storage SyncLoad IPC"),
mSuffix(aOriginSuffix),
mOrigin(aOriginNoSuffix),
mKeys(aKeys),
mValues(aValues),
mRv(rv),
mLoaded(false),
mLoadedCount(aAlreadyLoadedCount) {
// Precaution
*mRv = NS_ERROR_UNEXPECTED;
}
virtual const nsCString Origin() const override {
return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
}
virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
virtual const nsCString& OriginSuffix() const override { return mSuffix; }
virtual bool Loaded() override { return mLoaded; }
virtual uint32_t LoadedCount() override { return mLoadedCount; }
virtual bool LoadItem(const nsAString& aKey,
const nsAString& aValue) override {
// Called on the aCache background thread
MOZ_ASSERT(!mLoaded);
if (mLoaded) {
return false;
}
++mLoadedCount;
mKeys->AppendElement(aKey);
mValues->AppendElement(aValue);
return true;
}
virtual void LoadDone(nsresult aRv) override {
// Called on the aCache background thread
MonitorAutoLock monitor(mMonitor);
MOZ_ASSERT(!mLoaded && mRv);
mLoaded = true;
if (mRv) {
*mRv = aRv;
mRv = nullptr;
}
monitor.Notify();
}
virtual void LoadWait() override {
// Called on the main thread, exits after LoadDone() call
MonitorAutoLock monitor(mMonitor);
while (!mLoaded) {
monitor.Wait();
}
}
private:
Monitor mMonitor MOZ_UNANNOTATED;
nsCString mSuffix, mOrigin;
nsTArray<nsString>* mKeys;
nsTArray<nsString>* mValues;
nsresult* mRv;
bool mLoaded;
uint32_t mLoadedCount;
};
} // namespace
mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
nsTArray<nsString>* aValues, nsresult* aRv) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
RefPtr<SyncLoadCacheHelper> cache(
new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix,
aAlreadyLoadedCount, aKeys, aValues, aRv));
storageThread->SyncPreload(cache, true);
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const nsAString& aKey, const nsAString& aValue) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = storageThread->AsyncAddItem(
NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
if (NS_FAILED(rv) && mIPCOpen) {
mozilla::Unused << SendError(rv);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const nsAString& aKey, const nsAString& aValue) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = storageThread->AsyncUpdateItem(
NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
if (NS_FAILED(rv) && mIPCOpen) {
mozilla::Unused << SendError(rv);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
const nsAString& aKey) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = storageThread->AsyncRemoveItem(
NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
if (NS_FAILED(rv) && mIPCOpen) {
mozilla::Unused << SendError(rv);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv =
storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
if (NS_FAILED(rv) && mIPCOpen) {
mozilla::Unused << SendError(rv);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
StorageDBThread* storageThread = StorageDBThread::Get(mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
storageThread->AsyncFlush();
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
storageThread->AsyncClearAll();
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
const nsACString& aOriginNoSuffix) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
return IPC_OK();
}
mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes(
const OriginAttributesPattern& aPattern) {
StorageDBThread* storageThread =
StorageDBThread::GetOrCreate(mProfilePath, mPrivateBrowsingId);
if (!storageThread) {
return IPC_FAIL_NO_REASON(this);
}
storageThread->AsyncClearMatchingOriginAttributes(aPattern);
return IPC_OK();
}
void StorageDBParent::Observe(const nsACString& aTopic,
const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
if (mIPCOpen) {
mozilla::Unused << SendObserve(aTopic, aOriginAttributesPattern,
aOriginScope);
}
}
namespace {
// Results must be sent back on the main thread
class LoadRunnable : public Runnable {
public:
enum TaskType { loadItem, loadDone };
LoadRunnable(StorageDBParent* aParent, TaskType aType,
const nsACString& aOriginSuffix,
const nsACString& aOriginNoSuffix,
const nsAString& aKey = u""_ns, const nsAString& aValue = u""_ns)
: Runnable("dom::LoadRunnable"),
mParent(aParent),
mType(aType),
mSuffix(aOriginSuffix),
mOrigin(aOriginNoSuffix),
mKey(aKey),
mValue(aValue),
mRv(NS_ERROR_NOT_INITIALIZED) {}
LoadRunnable(StorageDBParent* aParent, TaskType aType,
const nsACString& aOriginSuffix,
const nsACString& aOriginNoSuffix, nsresult aRv)
: Runnable("dom::LoadRunnable"),
mParent(aParent),
mType(aType),
mSuffix(aOriginSuffix),
mOrigin(aOriginNoSuffix),
mRv(aRv) {}
private:
RefPtr<StorageDBParent> mParent;
TaskType mType;
nsCString mSuffix, mOrigin;
nsString mKey;
nsString mValue;
nsresult mRv;
NS_IMETHOD Run() override {
if (!mParent->IPCOpen()) {
return NS_OK;
}
switch (mType) {
case loadItem:
mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey,
mValue);
break;
case loadDone:
mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
break;
}
mParent = nullptr;
return NS_OK;
}
};
} // namespace
// StorageDBParent::CacheParentBridge
const nsCString StorageDBParent::CacheParentBridge::Origin() const {
return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
}
bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
const nsAString& aValue) {
if (mLoaded) {
return false;
}
++mLoadedCount;
RefPtr<LoadRunnable> r =
new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
mOriginNoSuffix, aKey, aValue);
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
return true;
}
void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) {
// Prevent send of duplicate LoadDone.
if (mLoaded) {
return;
}
mLoaded = true;
RefPtr<LoadRunnable> r = new LoadRunnable(
mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
}
void StorageDBParent::CacheParentBridge::LoadWait() {
// Should never be called on this implementation
MOZ_ASSERT(false);
}
// XXX Fix me!
// This should be just:
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
// But due to different strings used for refcount logging and different return
// types, this is done manually for now.
NS_IMETHODIMP_(void)
StorageDBParent::CacheParentBridge::Release(void) {
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
if (0 == count) {
mRefCnt = 1; /* stabilize */
/* enable this to find non-threadsafe destructors: */
/* NS_ASSERT_OWNINGTHREAD(_class); */
Destroy();
}
}
void StorageDBParent::CacheParentBridge::Destroy() {
if (mOwningEventTarget->IsOnCurrentThread()) {
delete this;
return;
}
RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
"CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy);
MOZ_ALWAYS_SUCCEEDS(
mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
}
// StorageDBParent::UsageParentBridge
namespace {
class UsageRunnable : public Runnable {
public:
UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope,
const int64_t& aUsage)
: Runnable("dom::UsageRunnable"),
mParent(aParent),
mOriginScope(aOriginScope),
mUsage(aUsage) {}
private:
NS_IMETHOD Run() override {
if (!mParent->IPCOpen()) {
return NS_OK;
}
mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
mParent = nullptr;
return NS_OK;
}
RefPtr<StorageDBParent> mParent;
nsCString mOriginScope;
int64_t mUsage;
};
} // namespace
void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) {
RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
}
// XXX Fix me!
// This should be just:
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
// But due to different strings used for refcount logging, this is done manually
// for now.
NS_IMETHODIMP_(MozExternalRefCountType)
StorageDBParent::UsageParentBridge::Release(void) {
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "StorageUsageBridge");
if (count == 0) {
Destroy();
return 0;
}
return count;
}
void StorageDBParent::UsageParentBridge::Destroy() {
if (mOwningEventTarget->IsOnCurrentThread()) {
delete this;
return;
}
RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
"UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy);
MOZ_ALWAYS_SUCCEEDS(
mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
}
void StorageDBParent::ObserverSink::Start() {
::mozilla::ipc::AssertIsOnBackgroundThread();
RefPtr<Runnable> runnable =
NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this,
&StorageDBParent::ObserverSink::AddSink);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
void StorageDBParent::ObserverSink::Stop() {
::mozilla::ipc::AssertIsOnBackgroundThread();
mActor = nullptr;
RefPtr<Runnable> runnable =
NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this,
&StorageDBParent::ObserverSink::RemoveSink);
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
}
void StorageDBParent::ObserverSink::AddSink() {
MOZ_ASSERT(NS_IsMainThread());
StorageObserver* observer = StorageObserver::Self();
if (observer) {
observer->AddSink(this);
}
}
void StorageDBParent::ObserverSink::RemoveSink() {
MOZ_ASSERT(NS_IsMainThread());
StorageObserver* observer = StorageObserver::Self();
if (observer) {
observer->RemoveSink(this);
}
}
void StorageDBParent::ObserverSink::Notify(
const nsACString& aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
::mozilla::ipc::AssertIsOnBackgroundThread();
if (mActor) {
mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
}
}
nsresult StorageDBParent::ObserverSink::Observe(
const char* aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>(
"StorageDBParent::ObserverSink::Observe2", this,
&StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern,
aOriginScope);
MOZ_ALWAYS_SUCCEEDS(
mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
return NS_OK;
}
SessionStorageObserverParent::SessionStorageObserverParent()
: mActorDestroyed(false) {
MOZ_ASSERT(NS_IsMainThread());
StorageObserver* observer = StorageObserver::Self();
if (observer) {
observer->AddSink(this);
}
}
SessionStorageObserverParent::~SessionStorageObserverParent() {
MOZ_ASSERT(mActorDestroyed);
StorageObserver* observer = StorageObserver::Self();
if (observer) {
observer->RemoveSink(this);
}
}
void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mActorDestroyed);
mActorDestroyed = true;
}
mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mActorDestroyed);
IProtocol* mgr = Manager();
if (!PSessionStorageObserverParent::Send__delete__(this)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
nsresult SessionStorageObserverParent::Observe(
const char* aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
MOZ_ASSERT(NS_IsMainThread());
if (!mActorDestroyed) {
mozilla::Unused << SendObserve(nsDependentCString(aTopic),
aOriginAttributesPattern, aOriginScope);
}
return NS_OK;
}
SessionStorageCacheParent::SessionStorageCacheParent(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsACString& aOriginKey, SessionStorageManagerParent* aActor)
: mPrincipalInfo(aPrincipalInfo),
mOriginKey(aOriginKey),
mManagerActor(aActor) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
}
SessionStorageCacheParent::~SessionStorageCacheParent() = default;
void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
::mozilla::ipc::AssertIsOnBackgroundThread();
mManagerActor = nullptr;
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad(
nsTArray<SSSetItemInfo>* aData) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
mLoadReceived.Flip();
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
MOZ_ASSERT(manager);
OriginAttributes attrs;
MOZ_ALWAYS_TRUE(
StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs));
nsAutoCString originAttrs;
attrs.CreateSuffix(originAttrs);
manager->CopyDataToContentProcess(originAttrs, mOriginKey, *aData);
return IPC_OK();
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint(
nsTArray<SSWriteInfo>&& aWriteInfos) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
MOZ_ASSERT(manager);
OriginAttributes attrs;
StoragePrincipalHelper::GetOriginAttributes(mPrincipalInfo, attrs);
nsAutoCString originAttrs;
attrs.CreateSuffix(originAttrs);
manager->UpdateData(originAttrs, mOriginKey, aWriteInfos);
return IPC_OK();
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
mManagerActor = nullptr;
IProtocol* mgr = Manager();
if (!PBackgroundSessionStorageCacheParent::Send__delete__(this)) {
return IPC_FAIL(
mgr, "Failed to delete PBackgroundSessionStorageCacheParent actor");
}
return IPC_OK();
}
SessionStorageManagerParent::SessionStorageManagerParent(uint64_t aTopContextId)
: mBackgroundManager(
BackgroundSessionStorageManager::GetOrCreate(aTopContextId)) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mBackgroundManager);
mBackgroundManager->AddParticipatingActor(this);
}
SessionStorageManagerParent::~SessionStorageManagerParent() = default;
void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
::mozilla::ipc::AssertIsOnBackgroundThread();
if (mBackgroundManager) {
mBackgroundManager->RemoveParticipatingActor(this);
}
mBackgroundManager = nullptr;
}
already_AddRefed<PBackgroundSessionStorageCacheParent>
SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent(
const PrincipalInfo& aPrincipalInfo, const nsACString& aOriginKey) {
return MakeAndAddRef<SessionStorageCacheParent>(aPrincipalInfo, aOriginKey,
this);
}
BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager()
const {
return mBackgroundManager;
}
mozilla::ipc::IPCResult SessionStorageManagerParent::RecvClearStorages(
const OriginAttributesPattern& aPattern, const nsACString& aOriginScope) {
::mozilla::ipc::AssertIsOnBackgroundThread();
mBackgroundManager->ClearStorages(aPattern, aOriginScope);
return IPC_OK();
}
mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(mBackgroundManager);
mBackgroundManager->RemoveParticipatingActor(this);
mBackgroundManager = nullptr;
IProtocol* mgr = Manager();
if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) {
return IPC_FAIL(
mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor");
}
return IPC_OK();
}
/*******************************************************************************
* Exported functions
******************************************************************************/
PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
RefPtr<LocalStorageCacheParent> actor = new LocalStorageCacheParent(
aPrincipalInfo, aOriginKey, aPrivateBrowsingId);
// Transfer ownership to IPDL.
return actor.forget().take();
}
mozilla::ipc::IPCResult RecvPBackgroundLocalStorageCacheConstructor(
mozilla::ipc::PBackgroundParent* aBackgroundActor,
PBackgroundLocalStorageCacheParent* aActor,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsACString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
auto* actor = static_cast<LocalStorageCacheParent*>(aActor);
if (!gLocalStorageCacheParents) {
gLocalStorageCacheParents = new LocalStorageCacheParentHashtable();
}
gLocalStorageCacheParents->GetOrInsertNew(aOriginKey)->AppendElement(actor);
// We are currently trusting the content process not to lie to us. It is
// future work to consult the ClientManager to determine whether this is a
// legitimate origin for the content process.
return IPC_OK();
}
bool DeallocPBackgroundLocalStorageCacheParent(
PBackgroundLocalStorageCacheParent* aActor) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
// Transfer ownership back from IPDL.
RefPtr<LocalStorageCacheParent> actor =
dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor));
return true;
}
PBackgroundStorageParent* AllocPBackgroundStorageParent(
const nsAString& aProfilePath, const uint32_t& aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
if (NS_WARN_IF(NextGenLocalStorageEnabled()) ||
NS_WARN_IF(aPrivateBrowsingId >= kPrivateBrowsingIdCount)) {
return nullptr;
}
return new StorageDBParent(aProfilePath, aPrivateBrowsingId);
}
mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor(
PBackgroundStorageParent* aActor, const nsAString& aProfilePath,
const uint32_t& aPrivateBrowsingId) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aPrivateBrowsingId < kPrivateBrowsingIdCount);
MOZ_ASSERT(!NextGenLocalStorageEnabled());
auto* actor = static_cast<StorageDBParent*>(aActor);
actor->Init();
return IPC_OK();
}
bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) {
::mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
StorageDBParent* actor = static_cast<StorageDBParent*>(aActor);
actor->ReleaseIPDLReference();
return true;
}
PSessionStorageObserverParent* AllocPSessionStorageObserverParent() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<SessionStorageObserverParent> actor =
new SessionStorageObserverParent();
// Transfer ownership to IPDL.
return actor.forget().take();
}
bool RecvPSessionStorageObserverConstructor(
PSessionStorageObserverParent* aActor) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
return true;
}
bool DeallocPSessionStorageObserverParent(
PSessionStorageObserverParent* aActor) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
// Transfer ownership back from IPDL.
RefPtr<SessionStorageObserverParent> actor =
dont_AddRef(static_cast<SessionStorageObserverParent*>(aActor));
return true;
}
already_AddRefed<PBackgroundSessionStorageManagerParent>
AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) {
return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId);
}
} // namespace mozilla::dom