Bug 1654080 - Use PBackground for syncing SessionStorageCache and use LSWriteOptimizer to send data changes; r=dom-workers-and-storage-reviewers,janv,nika

This patch does:
- Use LSWriteOptimizer
- Remove SessionStorageService since it's unused.
- Move IPC from PContent to PBackground
(by SessionStorageManager{Child, Parent} and SessionStorageCache{Child, Parent}).
- Extract SessionStorageManagerBase and add PBackgroundSessionStorageManager.
- Expose a getter function to get a BackgroundParentManager for top context id
on the parent.

IPC
- Before this patch:
  - Copy from parent while loading a document.
    - Mark cache entry on the parent process as loaded by the child id.
  - Update change on checkpoint.
  - Unmark cache entry on the parent process as unloaded for the child id while
  the parent actor is destorying.
- After this patch:
  - Sync IPC load in the first SessionStorage operation.
  - Update change on checkpoint

`BackgroundSessionStorageManager`'s lifecycle on the parent process.
- Create by `SessionStorageManagerParent` and register to the `sManagers`.
- Hold by `SessionStorageManagerParent` and `sManagers`.
- Remove from the `sManagers` while the corresponding `BrowsingContext` is
destructed (on the parent process).

Depends on D89341

Differential Revision: https://phabricator.services.mozilla.com/D89342
This commit is contained in:
Tom Tung 2020-10-14 00:19:33 +00:00
Родитель 4ca9a505c9
Коммит 45a97b5b83
32 изменённых файлов: 1382 добавлений и 439 удалений

Просмотреть файл

@ -20,6 +20,7 @@
#include "mozilla/dom/MediaControlService.h"
#include "mozilla/dom/ContentPlaybackController.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/net/DocumentLoadListener.h"
#include "mozilla/NullPrincipal.h"
@ -744,6 +745,10 @@ void CanonicalBrowsingContext::CanonicalDiscard() {
mTabMediaController->Shutdown();
mTabMediaController = nullptr;
}
if (IsTop()) {
BackgroundSessionStorageManager::RemoveManager(Id());
}
}
void CanonicalBrowsingContext::NotifyStartDelayedAutoplayMedia() {

Просмотреть файл

@ -4,6 +4,7 @@
* 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 "mozilla/dom/PGamepadEventChannelChild.h"
#include "nsRefPtrHashtable.h"
#ifndef mozilla_dom_GamepadEventChannelChild_h_
# define mozilla_dom_GamepadEventChannelChild_h_

Просмотреть файл

@ -3538,20 +3538,6 @@ mozilla::ipc::IPCResult ContentChild::RecvUpdateMediaControlAction(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvSessionStorageData(
const uint64_t aTopContextId, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData) {
if (const RefPtr<BrowsingContext> topContext =
BrowsingContext::Get(aTopContextId)) {
topContext->GetSessionStorageManager()->LoadSessionStorageData(
nullptr, aOriginAttrs, aOriginKey, aDefaultData, aSessionData);
} else {
NS_WARNING("Got session storage data for a discarded session");
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvOnAllowAccessFor(
const MaybeDiscarded<BrowsingContext>& aContext,
const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,

Просмотреть файл

@ -649,11 +649,6 @@ class ContentChild final : public PContentChild,
return mBrowsingContextFieldEpoch;
}
mozilla::ipc::IPCResult RecvSessionStorageData(
uint64_t aTopContextId, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData);
mozilla::ipc::IPCResult RecvOnAllowAccessFor(
const MaybeDiscarded<BrowsingContext>& aContext,
const nsCString& aTrackingOrigin, uint32_t aCookieBehavior,

Просмотреть файл

@ -5818,11 +5818,6 @@ nsresult ContentParent::AboutToLoadHttpFtpDocumentForChild(
rv = loadInfo->GetTargetBrowsingContext(getter_AddRefs(browsingContext));
NS_ENSURE_SUCCESS(rv, rv);
if (browsingContext && !browsingContext->IsDiscarded()) {
browsingContext->GetSessionStorageManager()
->SendSessionStorageDataToContentProcess(this, principal);
}
if (!NextGenLocalStorageEnabled()) {
return NS_OK;
}
@ -6404,20 +6399,6 @@ mozilla::ipc::IPCResult ContentParent::RecvGetModulesTrust(
#endif // defined(XP_WIN)
}
mozilla::ipc::IPCResult ContentParent::RecvSessionStorageData(
const uint64_t aTopContextId, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData) {
if (const RefPtr<BrowsingContext> topContext =
BrowsingContext::Get(aTopContextId)) {
topContext->GetSessionStorageManager()->LoadSessionStorageData(
this, aOriginAttrs, aOriginKey, aDefaultData, aSessionData);
} else {
NS_WARNING("Got session storage data for a discarded session");
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvCreateBrowsingContext(
uint64_t aGroupId, BrowsingContext::IPCInitializer&& aInit) {
RefPtr<WindowGlobalParent> parent;

Просмотреть файл

@ -1321,11 +1321,6 @@ class ContentParent final
ModulePaths&& aModPaths, bool aRunAtNormalPriority,
GetModulesTrustResolver&& aResolver);
mozilla::ipc::IPCResult RecvSessionStorageData(
uint64_t aTopContextId, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData);
mozilla::ipc::IPCResult RecvReportServiceWorkerShutdownProgress(
uint32_t aShutdownStateId,
ServiceWorkerShutdownState::Progress aProgress);

Просмотреть файл

@ -365,12 +365,6 @@ struct PostMessageData
uint64_t innerWindowId;
};
struct KeyValuePair
{
nsString key;
nsString value;
};
union SyncedContextInitializer
{
BrowsingContextInitializer;
@ -1790,13 +1784,6 @@ both:
ClonedOrErrorMessageData aMessage,
PostMessageData aData);
/**
* Move sessionStorage data between parent and content processes. See
* SessionStorageManager documentation for more details.
*/
async SessionStorageData(uint64_t aTopContextId, nsCString aOriginAttrs,
nsCString aOriginKey, KeyValuePair[] aDefaultData,
KeyValuePair[] aSessionData);
async CommitWindowContextTransaction(MaybeDiscardedWindowContext aContext,
WindowContextTransaction aTransaction,
uint64_t aEpoch);

Просмотреть файл

@ -21,7 +21,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ClientManagerService.h"
#include "mozilla/dom/FlippedOnce.h"
#include "mozilla/dom/LSWriteOptimizer.h"
#include "mozilla/dom/LSWriteOptimizerImpl.h"
#include "mozilla/dom/PBackgroundLSDatabaseParent.h"
#include "mozilla/dom/PBackgroundLSObserverParent.h"
#include "mozilla/dom/PBackgroundLSRequestParent.h"

Просмотреть файл

@ -9,7 +9,7 @@
#include "ActorsChild.h"
#include "LocalStorageCommon.h"
#include "LSDatabase.h"
#include "LSWriteOptimizer.h"
#include "LSWriteOptimizerImpl.h"
#include "mozilla/dom/PBackgroundLSSnapshot.h"
#include "nsContentUtils.h"

Просмотреть файл

@ -63,52 +63,5 @@ void LSWriteOptimizerBase::GetSortedWriteInfos(
}
}
template <typename T, typename U>
void LSWriteOptimizer<T, U>::InsertItem(const nsAString& aKey, const T& aValue,
int64_t aDelta) {
AssertIsOnOwningThread();
WriteInfo* existingWriteInfo;
UniquePtr<WriteInfo> newWriteInfo;
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
existingWriteInfo->GetType() == WriteInfo::DeleteItem) {
// We could just simply replace the deletion with ordinary update, but that
// would preserve item's original position/index. Imagine a case when we
// have only one existing key k1. Now let's create a new optimizer and
// remove k1, add k2 and add k1 back. The final order should be k2, k1
// (ordinary update would produce k1, k2). So we need to differentiate
// between normal update and "optimized" update which resulted from a
// deletion followed by an insertion. We use the UpdateWithMove flag for
// this.
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
/* aUpdateWithMove */ true);
} else {
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
}
mWriteInfos.Put(aKey, std::move(newWriteInfo));
mTotalDelta += aDelta;
}
template <typename T, typename U>
void LSWriteOptimizer<T, U>::UpdateItem(const nsAString& aKey, const T& aValue,
int64_t aDelta) {
AssertIsOnOwningThread();
WriteInfo* existingWriteInfo;
UniquePtr<WriteInfo> newWriteInfo;
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
existingWriteInfo->GetType() == WriteInfo::InsertItem) {
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
} else {
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
/* aUpdateWithMove */ false);
}
mWriteInfos.Put(aKey, std::move(newWriteInfo));
mTotalDelta += aDelta;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,66 @@
/* -*- 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/. */
#ifndef mozilla_dom_localstorage_LSWriteOptimizerImpl_h
#define mozilla_dom_localstorage_LSWriteOptimizerImpl_h
#include "LSWriteOptimizer.h"
namespace mozilla {
namespace dom {
template <typename T, typename U>
void LSWriteOptimizer<T, U>::InsertItem(const nsAString& aKey, const T& aValue,
int64_t aDelta) {
AssertIsOnOwningThread();
WriteInfo* existingWriteInfo;
UniquePtr<WriteInfo> newWriteInfo;
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
existingWriteInfo->GetType() == WriteInfo::DeleteItem) {
// We could just simply replace the deletion with ordinary update, but
// that
// would preserve item's original position/index. Imagine a case when we
// have only one existing key k1. Now let's create a new optimizer and
// remove k1, add k2 and add k1 back. The final order should be k2, k1
// (ordinary update would produce k1, k2). So we need to differentiate
// between normal update and "optimized" update which resulted from a
// deletion followed by an insertion. We use the UpdateWithMove flag for
// this.
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
/* aUpdateWithMove */ true);
} else {
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
}
mWriteInfos.Put(aKey, std::move(newWriteInfo));
mTotalDelta += aDelta;
}
template <typename T, typename U>
void LSWriteOptimizer<T, U>::UpdateItem(const nsAString& aKey, const T& aValue,
int64_t aDelta) {
AssertIsOnOwningThread();
WriteInfo* existingWriteInfo;
UniquePtr<WriteInfo> newWriteInfo;
if (mWriteInfos.Get(aKey, &existingWriteInfo) &&
existingWriteInfo->GetType() == WriteInfo::InsertItem) {
newWriteInfo = MakeUnique<InsertItemInfo>(NextSerialNumber(), aKey, aValue);
} else {
newWriteInfo = MakeUnique<UpdateItemInfo>(NextSerialNumber(), aKey, aValue,
/* aUpdateWithMove */ false);
}
mWriteInfos.Put(aKey, std::move(newWriteInfo));
mTotalDelta += aDelta;
}
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_localstorage_LSWriteOptimizerImpl_h

Просмотреть файл

@ -40,6 +40,7 @@ EXPORTS.mozilla.dom += [
'LSSnapshot.h',
'LSValue.h',
'LSWriteOptimizer.h',
'LSWriteOptimizerImpl.h',
'SnappyUtils.h',
]

Просмотреть файл

@ -0,0 +1,68 @@
/* 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 protocol PBackground;
include protocol PBackgroundSessionStorageManager;
namespace mozilla {
namespace dom {
struct SSSetItemInfo
{
nsString key;
nsString value;
};
struct SSRemoveItemInfo
{
nsString key;
};
struct SSClearInfo
{
};
/**
* Union of SessionStorage mutation types.
*/
union SSWriteInfo
{
SSSetItemInfo;
SSRemoveItemInfo;
SSClearInfo;
};
sync refcounted protocol PBackgroundSessionStorageCache
{
manager PBackgroundSessionStorageManager;
parent:
async DeleteMe();
/**
* Copy SessionStorageCache from the parent process to the content process.
* See SessionStorageManager documentation for more details.
*
* This needs to be synchronous because SessionStorage's semantics are
* synchronous. Note that the BackgroundSessionStorageManager in the
* PBackground parent already has the answers to this request immediately
* available without needing to consult any other threads or perform any I/O.
*/
sync Load()
returns (SSSetItemInfo[] aDefaultData, SSSetItemInfo[] aSessionData);
/**
* Send changes for SessionStorageCache from a content process to the parent
* process so that the data in the parent can be updated to be in sync with
* the content. See SessionStorageManager documentation for more details.
*/
async Checkpoint(SSWriteInfo[] aDefaultWriteInfos,
SSWriteInfo[] aSessionWriteInfos);
child:
async __delete__();
};
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,26 @@
/* 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 protocol PBackground;
include protocol PBackgroundSessionStorageCache;
namespace mozilla {
namespace dom {
sync refcounted protocol PBackgroundSessionStorageManager
{
manager PBackground;
manages PBackgroundSessionStorageCache;
parent:
async PBackgroundSessionStorageCache(nsCString aOriginAttrs, nsCString aOriginKey);
async DeleteMe();
child:
async __delete__();
};
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -48,6 +48,11 @@ SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
SessionStorage::~SessionStorage() = default;
int64_t SessionStorage::GetOriginQuotaUsage() const {
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
return mCache->GetOriginQuotaUsage(DATASET);
}
@ -58,6 +63,12 @@ uint32_t SessionStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
return 0;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return 0;
}
return mCache->Length(DATASET);
}
@ -68,6 +79,12 @@ void SessionStorage::Key(uint32_t aIndex, nsAString& aResult,
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
mCache->Key(DATASET, aIndex, aResult);
}
@ -79,6 +96,12 @@ void SessionStorage::GetItem(const nsAString& aKey, nsAString& aResult,
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
mCache->GetItem(DATASET, aKey, aResult);
}
@ -89,6 +112,13 @@ void SessionStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
// return just an empty array
aKeys.Clear();
return;
}
mCache->GetKeys(DATASET, aKeys);
}
@ -100,8 +130,14 @@ void SessionStorage::SetItem(const nsAString& aKey, const nsAString& aValue,
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
nsString oldValue;
nsresult rv = mCache->SetItem(DATASET, aKey, aValue, oldValue);
rv = mCache->SetItem(DATASET, aKey, aValue, oldValue);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
@ -122,8 +158,14 @@ void SessionStorage::RemoveItem(const nsAString& aKey,
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
nsString oldValue;
nsresult rv = mCache->RemoveItem(DATASET, aKey, oldValue);
rv = mCache->RemoveItem(DATASET, aKey, oldValue);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
@ -139,6 +181,12 @@ void SessionStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
return;
}
nsresult rv = EnsureCacheLoadedOrCloned();
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return;
}
mCache->Clear(DATASET);
BroadcastChangeNotification(VoidString(), VoidString(), VoidString());
}
@ -149,9 +197,8 @@ void SessionStorage::BroadcastChangeNotification(const nsAString& aKey,
NotifyChange(this, StoragePrincipal(), aKey, aOldValue, aNewValue,
u"sessionStorage", mDocumentURI, mIsPrivate, false);
// Sync changes on SessionStorageCache to the parent process at the next
// statble state.
if (XRE_IsContentProcess()) {
// Sync changes on SessionStorageCache at the next statble state.
if (mManager->CanLoadData()) {
MaybeScheduleStableStateCallback();
}
}
@ -166,7 +213,6 @@ bool SessionStorage::IsForkOf(const Storage* aOther) const {
}
void SessionStorage::MaybeScheduleStableStateCallback() {
MOZ_ASSERT(XRE_IsContentProcess());
AssertIsOnOwningThread();
if (!mHasPendingStableStateCallback) {
@ -179,12 +225,36 @@ void SessionStorage::MaybeScheduleStableStateCallback() {
}
void SessionStorage::StableStateCallback() {
MOZ_ASSERT(XRE_IsContentProcess());
AssertIsOnOwningThread();
MOZ_ASSERT(mHasPendingStableStateCallback);
MOZ_ASSERT(mManager);
MOZ_ASSERT(mManager->CanLoadData());
MOZ_ASSERT(mCache);
mHasPendingStableStateCallback = false;
mManager->SendSessionStorageDataToParentProcess(*Principal(), *mCache);
mManager->CheckpointData(*Principal(), *mCache);
}
nsresult SessionStorage::EnsureCacheLoadedOrCloned() const {
AssertIsOnOwningThread();
MOZ_ASSERT(mManager);
if (!mManager->CanLoadData()) {
return NS_OK;
}
// Ensure manager actor.
nsresult rv = mManager->EnsureManager();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Ensure cache is loaded or cloned.
if (mCache->WasLoadedOrCloned()) {
return NS_OK;
}
return mManager->LoadData(*Principal(), *mCache);
}
} // namespace dom

Просмотреть файл

@ -72,6 +72,8 @@ class SessionStorage final : public Storage {
void StableStateCallback();
nsresult EnsureCacheLoadedOrCloned() const;
RefPtr<SessionStorageCache> mCache;
RefPtr<SessionStorageManager> mManager;

Просмотреть файл

@ -6,12 +6,92 @@
#include "SessionStorageCache.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/LSWriteOptimizer.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
namespace mozilla {
namespace dom {
SessionStorageCache::SessionStorageCache() = default;
void SSWriteOptimizer::Enumerate(nsTArray<SSWriteInfo>& aWriteInfos) {
AssertIsOnOwningThread();
// The mWriteInfos hash table contains all write infos, but it keeps them in
// an arbitrary order, which means write infos need to be sorted before being
// processed.
nsTArray<WriteInfo*> writeInfos;
GetSortedWriteInfos(writeInfos);
for (WriteInfo* writeInfo : writeInfos) {
switch (writeInfo->GetType()) {
case WriteInfo::InsertItem: {
auto* insertItemInfo = static_cast<InsertItemInfo*>(writeInfo);
SSSetItemInfo setItemInfo;
setItemInfo.key() = insertItemInfo->GetKey();
setItemInfo.value() = insertItemInfo->GetValue();
aWriteInfos.AppendElement(std::move(setItemInfo));
break;
}
case WriteInfo::UpdateItem: {
auto* updateItemInfo = static_cast<UpdateItemInfo*>(writeInfo);
if (updateItemInfo->UpdateWithMove()) {
// See the comment in LSWriteOptimizer::InsertItem for more details
// about the UpdateWithMove flag.
SSRemoveItemInfo removeItemInfo;
removeItemInfo.key() = updateItemInfo->GetKey();
aWriteInfos.AppendElement(std::move(removeItemInfo));
}
SSSetItemInfo setItemInfo;
setItemInfo.key() = updateItemInfo->GetKey();
setItemInfo.value() = updateItemInfo->GetValue();
aWriteInfos.AppendElement(std::move(setItemInfo));
break;
}
case WriteInfo::DeleteItem: {
auto* deleteItemInfo = static_cast<DeleteItemInfo*>(writeInfo);
SSRemoveItemInfo removeItemInfo;
removeItemInfo.key() = deleteItemInfo->GetKey();
aWriteInfos.AppendElement(std::move(removeItemInfo));
break;
}
case WriteInfo::Truncate: {
SSClearInfo clearInfo;
aWriteInfos.AppendElement(std::move(clearInfo));
break;
}
default:
MOZ_CRASH("Bad type!");
}
}
}
SessionStorageCache::SessionStorageCache()
: mActor(nullptr), mLoadedOrCloned(false) {}
SessionStorageCache::~SessionStorageCache() {
if (mActor) {
mActor->SendDeleteMeInternal();
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
}
}
SessionStorageCache::DataSet* SessionStorageCache::Set(
DataSetType aDataSetType) {
@ -64,9 +144,11 @@ void SessionStorageCache::GetKeys(DataSetType aDataSetType,
nsresult SessionStorageCache::SetItem(DataSetType aDataSetType,
const nsAString& aKey,
const nsAString& aValue,
nsString& aOldValue) {
nsString& aOldValue,
bool aRecordWriteInfo) {
int64_t delta = 0;
DataSet* dataSet = Set(aDataSetType);
MOZ_ASSERT(dataSet);
if (!dataSet->mKeys.Get(aKey, &aOldValue)) {
SetDOMStringToNull(aOldValue);
@ -87,14 +169,24 @@ nsresult SessionStorageCache::SetItem(DataSetType aDataSetType,
return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR;
}
if (aRecordWriteInfo && XRE_IsContentProcess()) {
if (DOMStringIsNull(aOldValue)) {
dataSet->mWriteOptimizer.InsertItem(aKey, aValue);
} else {
dataSet->mWriteOptimizer.UpdateItem(aKey, aValue);
}
}
dataSet->mKeys.Put(aKey, nsString(aValue));
return NS_OK;
}
nsresult SessionStorageCache::RemoveItem(DataSetType aDataSetType,
const nsAString& aKey,
nsString& aOldValue) {
nsString& aOldValue,
bool aRecordWriteInfo) {
DataSet* dataSet = Set(aDataSetType);
MOZ_ASSERT(dataSet);
if (!dataSet->mKeys.Get(aKey, &aOldValue)) {
return NS_SUCCESS_DOM_NO_OPERATION;
@ -104,38 +196,56 @@ nsresult SessionStorageCache::RemoveItem(DataSetType aDataSetType,
dataSet->ProcessUsageDelta(-(static_cast<int64_t>(aOldValue.Length()) +
static_cast<int64_t>(aKey.Length())));
if (aRecordWriteInfo && XRE_IsContentProcess()) {
dataSet->mWriteOptimizer.DeleteItem(aKey);
}
dataSet->mKeys.Remove(aKey);
return NS_OK;
}
void SessionStorageCache::Clear(DataSetType aDataSetType,
bool aByUserInteraction) {
bool aByUserInteraction,
bool aRecordWriteInfo) {
DataSet* dataSet = Set(aDataSetType);
MOZ_ASSERT(dataSet);
dataSet->ProcessUsageDelta(-dataSet->mOriginQuotaUsage);
if (aRecordWriteInfo && XRE_IsContentProcess()) {
dataSet->mWriteOptimizer.Truncate();
}
dataSet->mKeys.Clear();
}
void SessionStorageCache::ResetWriteInfos(DataSetType aDataSetType) {
Set(aDataSetType)->mWriteOptimizer.Reset();
}
already_AddRefed<SessionStorageCache> SessionStorageCache::Clone() const {
RefPtr<SessionStorageCache> cache = new SessionStorageCache();
cache->mDefaultSet.mOriginQuotaUsage = mDefaultSet.mOriginQuotaUsage;
for (auto iter = mDefaultSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) {
cache->mDefaultSet.mKeys.Put(iter.Key(), iter.Data());
cache->mDefaultSet.mWriteOptimizer.InsertItem(iter.Key(), iter.Data());
}
cache->mSessionSet.mOriginQuotaUsage = mSessionSet.mOriginQuotaUsage;
for (auto iter = mSessionSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) {
cache->mSessionSet.mKeys.Put(iter.Key(), iter.Data());
cache->mSessionSet.mWriteOptimizer.InsertItem(iter.Key(), iter.Data());
}
return cache.forget();
}
nsTArray<KeyValuePair> SessionStorageCache::SerializeData(
nsTArray<SSSetItemInfo> SessionStorageCache::SerializeData(
DataSetType aDataSetType) {
nsTArray<KeyValuePair> data;
nsTArray<SSSetItemInfo> data;
for (auto iter = Set(aDataSetType)->mKeys.Iter(); !iter.Done(); iter.Next()) {
KeyValuePair keyValuePair;
SSSetItemInfo keyValuePair;
keyValuePair.key() = iter.Key();
keyValuePair.value() = iter.Data();
data.EmplaceBack(std::move(keyValuePair));
@ -143,15 +253,74 @@ nsTArray<KeyValuePair> SessionStorageCache::SerializeData(
return data;
}
void SessionStorageCache::DeserializeData(DataSetType aDataSetType,
const nsTArray<KeyValuePair>& aData) {
Clear(aDataSetType, false);
nsTArray<SSWriteInfo> SessionStorageCache::SerializeWriteInfos(
DataSetType aDataSetType) {
nsTArray<SSWriteInfo> writeInfos;
Set(aDataSetType)->mWriteOptimizer.Enumerate(writeInfos);
return writeInfos;
}
void SessionStorageCache::DeserializeData(
DataSetType aDataSetType, const nsTArray<SSSetItemInfo>& aData) {
Clear(aDataSetType, false, /* aRecordWriteInfo */ false);
for (const auto& keyValuePair : aData) {
nsString oldValue;
SetItem(aDataSetType, keyValuePair.key(), keyValuePair.value(), oldValue);
SetItem(aDataSetType, keyValuePair.key(), keyValuePair.value(), oldValue,
false);
}
}
void SessionStorageCache::DeserializeWriteInfos(
DataSetType aDataSetType, const nsTArray<SSWriteInfo>& aInfos) {
for (const auto& writeInfo : aInfos) {
switch (writeInfo.type()) {
case SSWriteInfo::TSSSetItemInfo: {
const SSSetItemInfo& info = writeInfo.get_SSSetItemInfo();
nsString oldValue;
SetItem(aDataSetType, info.key(), info.value(), oldValue,
/* aRecordWriteInfo */ false);
break;
}
case SSWriteInfo::TSSRemoveItemInfo: {
const SSRemoveItemInfo& info = writeInfo.get_SSRemoveItemInfo();
nsString oldValue;
RemoveItem(aDataSetType, info.key(), oldValue,
/* aRecordWriteInfo */ false);
break;
}
case SSWriteInfo::TSSClearInfo: {
Clear(aDataSetType, false, /* aRecordWriteInfo */ false);
break;
}
default:
MOZ_CRASH("Should never get here!");
}
}
}
void SessionStorageCache::SetActor(SessionStorageCacheChild* aActor) {
AssertIsOnMainThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!mActor);
mActor = aActor;
}
void SessionStorageCache::ClearActor() {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
mActor = nullptr;
}
bool SessionStorageCache::DataSet::ProcessUsageDelta(int64_t aDelta) {
// Check limit per this origin
uint64_t newOriginUsage = mOriginQuotaUsage + aDelta;

Просмотреть файл

@ -7,12 +7,26 @@
#ifndef mozilla_dom_SessionStorageCache_h
#define mozilla_dom_SessionStorageCache_h
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/LSWriteOptimizerImpl.h"
#include "nsDataHashtable.h"
namespace mozilla {
namespace dom {
class KeyValuePair;
class SSSetItemInfo;
class SSWriteInfo;
class SessionStorageCacheChild;
/**
* Coalescing manipulation queue used by `SessionStorageCache`. Used by
* `SessionStorageCache` to buffer and coalesce manipulations before they
* are sent to the parent process.
*/
class SSWriteOptimizer final : public LSWriteOptimizer<nsAString, nsString> {
public:
void Enumerate(nsTArray<SSWriteInfo>& aWriteInfos);
};
class SessionStorageCache final {
public:
@ -37,35 +51,61 @@ class SessionStorageCache final {
void GetKeys(DataSetType aDataSetType, nsTArray<nsString>& aKeys);
nsresult SetItem(DataSetType aDataSetType, const nsAString& aKey,
const nsAString& aValue, nsString& aOldValue);
const nsAString& aValue, nsString& aOldValue,
bool aRecordWriteInfo = true);
nsresult RemoveItem(DataSetType aDataSetType, const nsAString& aKey,
nsString& aOldValue);
nsString& aOldValue, bool aRecordWriteInfo = true);
void Clear(DataSetType aDataSetType, bool aByUserInteraction = true);
void Clear(DataSetType aDataSetType, bool aByUserInteraction = true,
bool aRecordWriteInfo = true);
void ResetWriteInfos(DataSetType aDataSetType);
already_AddRefed<SessionStorageCache> Clone() const;
nsTArray<KeyValuePair> SerializeData(DataSetType aDataSetType);
nsTArray<SSSetItemInfo> SerializeData(DataSetType aDataSetType);
nsTArray<SSWriteInfo> SerializeWriteInfos(DataSetType aDataSetType);
void DeserializeData(DataSetType aDataSetType,
const nsTArray<KeyValuePair>& aData);
const nsTArray<SSSetItemInfo>& aData);
void DeserializeWriteInfos(DataSetType aDataSetType,
const nsTArray<SSWriteInfo>& aInfos);
void SetActor(SessionStorageCacheChild* aActor);
SessionStorageCacheChild* Actor() const { return mActor; }
void ClearActor();
void SetLoadedOrCloned() { mLoadedOrCloned = true; }
bool WasLoadedOrCloned() const { return mLoadedOrCloned; }
private:
~SessionStorageCache() = default;
~SessionStorageCache();
struct DataSet {
DataSet() : mOriginQuotaUsage(0) {}
bool ProcessUsageDelta(int64_t aDelta);
int64_t mOriginQuotaUsage;
nsDataHashtable<nsStringHashKey, nsString> mKeys;
SSWriteOptimizer mWriteOptimizer;
int64_t mOriginQuotaUsage;
};
DataSet* Set(DataSetType aDataSetType);
DataSet mDefaultSet;
DataSet mSessionSet;
SessionStorageCacheChild* mActor;
bool mLoadedOrCloned;
};
} // namespace dom

Просмотреть файл

@ -6,20 +6,80 @@
#include "SessionStorageManager.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/OriginAttributes.h"
#include "StorageIPC.h"
#include "SessionStorage.h"
#include "SessionStorageCache.h"
#include "SessionStorageObserver.h"
#include "SessionStorageService.h"
#include "StorageUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/OriginAttributes.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PBackgroundSessionStorageCache.h"
#include "mozilla/dom/PBackgroundSessionStorageManager.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "nsDataHashtable.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace dom {
using namespace StorageUtils;
// Parent process, background thread hashmap that stores top context id and
// manager pair.
static StaticAutoPtr<
nsRefPtrHashtable<nsUint64HashKey, BackgroundSessionStorageManager>>
sManagers;
bool RecvShutdownBackgroundSessionStorageManagers() {
AssertIsOnBackgroundThread();
sManagers = nullptr;
return true;
}
bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId) {
AssertIsOnBackgroundThread();
if (sManagers) {
sManagers->Remove(aTopContextId);
}
return true;
}
SessionStorageManagerBase::OriginRecord*
SessionStorageManagerBase::GetOriginRecord(
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
OriginKeyHashTable* table;
if (!mOATable.Get(aOriginAttrs, &table)) {
if (aMakeIfNeeded) {
table = new OriginKeyHashTable();
mOATable.Put(aOriginAttrs, table);
} else {
return nullptr;
}
}
OriginRecord* originRecord;
if (!table->Get(aOriginKey, &originRecord)) {
if (aMakeIfNeeded) {
originRecord = new OriginRecord();
if (aCloneFrom) {
originRecord->mCache = aCloneFrom->Clone();
} else {
originRecord->mCache = new SessionStorageCache();
}
table->Put(aOriginKey, originRecord);
} else {
return nullptr;
}
}
return originRecord;
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
@ -32,10 +92,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager)
SessionStorageManager::SessionStorageManager(
RefPtr<BrowsingContext> aBrowsingContext)
: mBrowsingContext(std::move(aBrowsingContext)) {
if (const auto service = SessionStorageService::Get()) {
service->RegisterSessionStorageManager(this);
}
: mBrowsingContext(std::move(aBrowsingContext)), mActor(nullptr) {
AssertIsOnMainThread();
StorageObserver* observer = StorageObserver::Self();
NS_ASSERTION(
@ -77,11 +135,170 @@ SessionStorageManager::~SessionStorageManager() {
observer->RemoveSink(this);
}
if (const auto service = SessionStorageService::Get()) {
service->UnregisterSessionStorageManager(this);
if (mActor) {
mActor->SendDeleteMeInternal();
MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
}
}
bool SessionStorageManager::CanLoadData() {
AssertIsOnMainThread();
return mBrowsingContext && !mBrowsingContext->IsDiscarded();
}
void SessionStorageManager::SetActor(SessionStorageManagerChild* aActor) {
AssertIsOnMainThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(!mActor);
mActor = aActor;
}
bool SessionStorageManager::ActorExists() const {
AssertIsOnMainThread();
return mActor;
}
void SessionStorageManager::ClearActor() {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
mActor = nullptr;
}
nsresult SessionStorageManager::EnsureManager() {
AssertIsOnMainThread();
MOZ_ASSERT(CanLoadData());
if (ActorExists()) {
return NS_OK;
}
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!backgroundActor)) {
return NS_ERROR_FAILURE;
}
RefPtr<SessionStorageManagerChild> actor =
new SessionStorageManagerChild(this);
MOZ_ASSERT(actor);
MOZ_ALWAYS_TRUE(
backgroundActor->SendPBackgroundSessionStorageManagerConstructor(
actor, mBrowsingContext->Top()->Id()));
SetActor(actor);
return NS_OK;
}
SessionStorageCacheChild* SessionStorageManager::EnsureCache(
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
SessionStorageCache& aCache) {
AssertIsOnMainThread();
MOZ_ASSERT(CanLoadData());
MOZ_ASSERT(ActorExists());
if (aCache.Actor()) {
return aCache.Actor();
}
RefPtr<SessionStorageCacheChild> actor =
new SessionStorageCacheChild(&aCache);
MOZ_ALWAYS_TRUE(mActor->SendPBackgroundSessionStorageCacheConstructor(
actor, aOriginAttrs, aOriginKey));
aCache.SetActor(actor);
return actor;
}
nsresult SessionStorageManager::LoadData(nsIPrincipal& aPrincipal,
SessionStorageCache& aCache) {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
nsAutoCString originKey;
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsAutoCString originAttributes;
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
auto* const originRecord =
GetOriginRecord(originAttributes, originKey, true, nullptr);
MOZ_ASSERT(originRecord);
if (originRecord->mLoaded) {
return NS_OK;
}
RefPtr<SessionStorageCacheChild> cacheActor =
EnsureCache(originAttributes, originKey, aCache);
nsTArray<SSSetItemInfo> defaultData;
nsTArray<SSSetItemInfo> sessionData;
if (!cacheActor->SendLoad(&defaultData, &sessionData)) {
return NS_ERROR_FAILURE;
}
originRecord->mCache->DeserializeData(SessionStorageCache::eDefaultSetType,
defaultData);
originRecord->mCache->DeserializeData(SessionStorageCache::eSessionSetType,
sessionData);
originRecord->mLoaded.Flip();
aCache.SetLoadedOrCloned();
return NS_OK;
}
void SessionStorageManager::CheckpointData(nsIPrincipal& aPrincipal,
SessionStorageCache& aCache) {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
nsAutoCString originKey;
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsAutoCString originAttributes;
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
return CheckpointDataInternal(originAttributes, originKey, aCache);
}
void SessionStorageManager::CheckpointDataInternal(
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
SessionStorageCache& aCache) {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
nsTArray<SSWriteInfo> defaultWriteInfos =
aCache.SerializeWriteInfos(SessionStorageCache::eDefaultSetType);
nsTArray<SSWriteInfo> sessionWriteInfos =
aCache.SerializeWriteInfos(SessionStorageCache::eSessionSetType);
if (defaultWriteInfos.IsEmpty() && sessionWriteInfos.IsEmpty()) {
return;
}
RefPtr<SessionStorageCacheChild> cacheActor =
EnsureCache(aOriginAttrs, aOriginKey, aCache);
Unused << cacheActor->SendCheckpoint(defaultWriteInfos, sessionWriteInfos);
aCache.ResetWriteInfos(SessionStorageCache::eDefaultSetType);
aCache.ResetWriteInfos(SessionStorageCache::eSessionSetType);
}
NS_IMETHODIMP
SessionStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal,
nsIPrincipal* aStoragePrincipal,
@ -126,37 +343,6 @@ nsresult SessionStorageManager::GetSessionStorageCacheHelper(
return NS_OK;
}
SessionStorageManager::OriginRecord* SessionStorageManager::GetOriginRecord(
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
OriginKeyHashTable* table;
if (!mOATable.Get(aOriginAttrs, &table)) {
if (aMakeIfNeeded) {
table = new OriginKeyHashTable();
mOATable.Put(aOriginAttrs, table);
} else {
return nullptr;
}
}
OriginRecord* originRecord;
if (!table->Get(aOriginKey, &originRecord)) {
if (aMakeIfNeeded) {
originRecord = new OriginRecord();
if (aCloneFrom) {
originRecord->mCache = aCloneFrom->Clone();
} else {
originRecord->mCache = new SessionStorageCache();
}
table->Put(aOriginKey, originRecord);
} else {
return nullptr;
}
}
return originRecord;
}
NS_IMETHODIMP
SessionStorageManager::CreateStorage(mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
@ -212,10 +398,33 @@ SessionStorageManager::CloneStorage(Storage* aStorage) {
return NS_ERROR_UNEXPECTED;
}
// ToDo: At the momnet, we clone the cache on the child process and then
// send the checkpoint. It would be nicer if we either serailizing all the
// data and sync to the parent process directly or clonig storage on the
// parnet process and sync it to the child process on demand.
RefPtr<SessionStorageCache> cache;
return GetSessionStorageCacheHelper(
nsresult rv = GetSessionStorageCacheHelper(
aStorage->StoragePrincipal(), true,
static_cast<SessionStorage*>(aStorage)->Cache(), &cache);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// If cache was cloned from other storage, then we shouldn't load the cache
// at the first access.
cache->SetLoadedOrCloned();
if (CanLoadData()) {
rv = EnsureManager();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
CheckpointData(*aStorage->StoragePrincipal(), *cache);
}
return rv;
}
NS_IMETHODIMP
@ -260,6 +469,13 @@ SessionStorageManager::CheckStorage(nsIPrincipal* aPrincipal, Storage* aStorage,
void SessionStorageManager::ClearStorages(
ClearStorageType aType, const OriginAttributesPattern& aPattern,
const nsACString& aOriginScope) {
if (CanLoadData()) {
nsresult rv = EnsureManager();
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
for (auto iter1 = mOATable.Iter(); !iter1.Done(); iter1.Next()) {
OriginAttributes oa;
DebugOnly<bool> ok = oa.PopulateFromSuffix(iter1.Key());
@ -281,85 +497,17 @@ void SessionStorageManager::ClearStorages(
MOZ_ASSERT(aType == eSessionOnly);
cache->Clear(SessionStorageCache::eSessionSetType, false);
}
if (CanLoadData()) {
MOZ_ASSERT(ActorExists());
CheckpointDataInternal(nsCString{iter1.Key()}, nsCString{iter2.Key()},
*cache);
}
}
}
}
}
void SessionStorageManager::SendSessionStorageDataToParentProcess(
nsIPrincipal& aPrincipal, SessionStorageCache& aSSCache) {
if (!mBrowsingContext || mBrowsingContext->IsDiscarded()) {
return;
}
nsAutoCString originKey;
nsresult rv = aPrincipal.GetStorageOriginKey(originKey);
if (NS_FAILED(rv)) {
return;
}
nsAutoCString originAttributes;
aPrincipal.OriginAttributesRef().CreateSuffix(originAttributes);
SendSessionStorageCache(ContentChild::GetSingleton(), originAttributes,
originKey, &aSSCache);
}
void SessionStorageManager::SendSessionStorageDataToContentProcess(
ContentParent* const aActor, nsIPrincipal* const aPrincipal) {
nsAutoCString originAttrs;
nsAutoCString originKey;
nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
aPrincipal->OriginAttributesRef().CreateSuffix(originAttrs);
if (NS_FAILED(rv)) {
return;
}
const auto originRecord =
GetOriginRecord(originAttrs, originKey, false, nullptr);
if (!originRecord) {
return;
}
const auto id = aActor->ChildID();
if (!originRecord->mKnownTo.Contains(id)) {
originRecord->mKnownTo.PutEntry(id);
SendSessionStorageCache(aActor, originAttrs, originKey,
originRecord->mCache);
}
}
template <typename Actor>
void SessionStorageManager::SendSessionStorageCache(
Actor* const aActor, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, SessionStorageCache* const aCache) {
nsTArray<KeyValuePair> defaultData =
aCache->SerializeData(SessionStorageCache::eDefaultSetType);
nsTArray<KeyValuePair> sessionData =
aCache->SerializeData(SessionStorageCache::eSessionSetType);
Unused << aActor->SendSessionStorageData(
mBrowsingContext->Id(), nsCString{aOriginAttrs}, nsCString{aOriginKey},
defaultData, sessionData);
}
void SessionStorageManager::LoadSessionStorageData(
ContentParent* const aSource, const nsACString& aOriginAttrs,
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData) {
const auto originRecord =
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
MOZ_ASSERT(originRecord);
if (aSource) {
originRecord->mKnownTo.RemoveEntry(aSource->ChildID());
}
originRecord->mCache->DeserializeData(SessionStorageCache::eDefaultSetType,
aDefaultData);
originRecord->mCache->DeserializeData(SessionStorageCache::eSessionSetType,
aSessionData);
}
nsresult SessionStorageManager::Observe(
const char* aTopic, const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) {
@ -399,11 +547,101 @@ nsresult SessionStorageManager::Observe(
return NS_OK;
}
RefPtr<BrowsingContext> SessionStorageManager::GetBrowsingContext() const {
return mBrowsingContext;
SessionStorageManager::OriginRecord::~OriginRecord() = default;
// static
void BackgroundSessionStorageManager::RemoveManager(uint64_t aTopContextId) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertIsOnMainThread();
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!backgroundActor)) {
return;
}
if (NS_WARN_IF(!backgroundActor->SendRemoveBackgroundSessionStorageManager(
aTopContextId))) {
return;
}
}
SessionStorageManager::OriginRecord::~OriginRecord() = default;
// static
BackgroundSessionStorageManager* BackgroundSessionStorageManager::GetOrCreate(
uint64_t aTopContextId) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertIsOnBackgroundThread();
if (!sManagers) {
sManagers = new nsRefPtrHashtable<nsUint64HashKey,
BackgroundSessionStorageManager>();
NS_DispatchToMainThread(NS_NewRunnableFunction(
"dom::BackgroundSessionStorageManager::GetOrCreate", [] {
RunOnShutdown(
[] {
PBackgroundChild* backgroundActor =
BackgroundChild::GetOrCreateForCurrentThread();
if (NS_WARN_IF(!backgroundActor)) {
return;
}
if (NS_WARN_IF(
!backgroundActor
->SendShutdownBackgroundSessionStorageManagers())) {
return;
}
},
ShutdownPhase::Shutdown);
}));
}
return sManagers->LookupForAdd(aTopContextId).OrInsert([] {
return new BackgroundSessionStorageManager();
});
}
BackgroundSessionStorageManager::BackgroundSessionStorageManager() {
MOZ_ASSERT(XRE_IsParentProcess());
AssertIsOnBackgroundThread();
}
BackgroundSessionStorageManager::~BackgroundSessionStorageManager() = default;
void BackgroundSessionStorageManager::CopyDataToContentProcess(
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
nsTArray<SSSetItemInfo>& aDefaultData,
nsTArray<SSSetItemInfo>& aSessionData) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertIsOnBackgroundThread();
auto* const originRecord =
GetOriginRecord(aOriginAttrs, aOriginKey, false, nullptr);
if (!originRecord) {
return;
}
aDefaultData =
originRecord->mCache->SerializeData(SessionStorageCache::eDefaultSetType);
aSessionData =
originRecord->mCache->SerializeData(SessionStorageCache::eSessionSetType);
}
void BackgroundSessionStorageManager::UpdateData(
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
const nsTArray<SSWriteInfo>& aDefaultWriteInfos,
const nsTArray<SSWriteInfo>& aSessionWriteInfos) {
MOZ_ASSERT(XRE_IsParentProcess());
AssertIsOnBackgroundThread();
auto* const originRecord =
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
MOZ_ASSERT(originRecord);
originRecord->mCache->DeserializeWriteInfos(
SessionStorageCache::eDefaultSetType, aDefaultWriteInfos);
originRecord->mCache->DeserializeWriteInfos(
SessionStorageCache::eSessionSetType, aSessionWriteInfos);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -7,22 +7,32 @@
#ifndef mozilla_dom_SessionStorageManager_h
#define mozilla_dom_SessionStorageManager_h
#include "StorageObserver.h"
#include "mozilla/dom/FlippedOnce.h"
#include "nsIDOMStorageManager.h"
#include "nsClassHashtable.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "StorageObserver.h"
namespace mozilla {
class OriginAttributesPattern;
namespace dom {
bool RecvShutdownBackgroundSessionStorageManagers();
bool RecvRemoveBackgroundSessionStorageManager(uint64_t aTopContextId);
class BrowsingContext;
class ContentParent;
class KeyValuePair;
class SSSetItemInfo;
class SSWriteInfo;
class SessionStorageCache;
class SessionStorageCacheChild;
class SessionStorageManagerChild;
class SessionStorageManagerParent;
class SessionStorageObserver;
struct OriginRecord;
// sessionStorage is a data store that's unique to each tab (i.e. top-level
// browsing context) and origin. Before the advent of Fission all the data
@ -33,17 +43,44 @@ class SessionStorageObserver;
// by navigating an iframe element). Therefore SessionStorageManager
// objects exist in both the parent and content processes.
//
// Whenever a content process terminates it sends its sessionStorage data
// to the parent process (see SessionStorageService); whenever a content
// process navigates to an origin for the first time in a given tab, the
// parent process sends it the saved data. To avoid sending the data
// multiple times, the parent process maintains a table of content
// processes that already received it; this table is empty in content
// processes.
// Whenever a write operation for SessionStorage executes, the content process
// sends the changes to the parent process at the next stable state. Whenever a
// content process navigates to an origin for the first time in a given tab, the
// parent process sends it the saved data. SessionStorageCache has a flag
// (mLoadedOrCloned) to ensure that it's only be loaded or cloned once.
//
// Note: the current implementation is expected to be replaced by a new
// implementation using LSNG.
class SessionStorageManager final : public nsIDOMSessionStorageManager,
class SessionStorageManagerBase {
public:
SessionStorageManagerBase() = default;
protected:
~SessionStorageManagerBase() = default;
struct OriginRecord {
OriginRecord() = default;
OriginRecord(OriginRecord&&) = default;
OriginRecord& operator=(OriginRecord&&) = default;
~OriginRecord();
RefPtr<SessionStorageCache> mCache;
// A flag to ensure that cache is only loaded once.
FlippedOnce<false> mLoaded;
};
OriginRecord* GetOriginRecord(const nsACString& aOriginAttrs,
const nsACString& aOriginKey,
bool aMakeIfNeeded,
SessionStorageCache* aCloneFrom);
using OriginKeyHashTable = nsClassHashtable<nsCStringHashKey, OriginRecord>;
nsClassHashtable<nsCStringHashKey, OriginKeyHashTable> mOATable;
};
class SessionStorageManager final : public SessionStorageManagerBase,
public nsIDOMSessionStorageManager,
public StorageObserverSink {
public:
explicit SessionStorageManager(RefPtr<BrowsingContext> aBrowsingContext);
@ -54,18 +91,19 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
NS_DECL_CYCLE_COLLECTION_CLASS(SessionStorageManager)
RefPtr<BrowsingContext> GetBrowsingContext() const;
bool CanLoadData();
void SendSessionStorageDataToParentProcess(nsIPrincipal& aPrincipal,
SessionStorageCache& aSSCache);
void SendSessionStorageDataToContentProcess(ContentParent* aActor,
nsIPrincipal* aPrincipal);
void SetActor(SessionStorageManagerChild* aActor);
void LoadSessionStorageData(ContentParent* aSource,
const nsACString& aOriginAttrs,
const nsACString& aOriginKey,
const nsTArray<KeyValuePair>& aDefaultData,
const nsTArray<KeyValuePair>& aSessionData);
bool ActorExists() const;
void ClearActor();
nsresult EnsureManager();
nsresult LoadData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
void CheckpointData(nsIPrincipal& aPrincipal, SessionStorageCache& aCache);
private:
~SessionStorageManager();
@ -75,15 +113,6 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
const nsAString& aOriginAttributesPattern,
const nsACString& aOriginScope) override;
enum ClearStorageType {
eAll,
eSessionOnly,
};
void ClearStorages(ClearStorageType aType,
const OriginAttributesPattern& aPattern,
const nsACString& aOriginScope);
nsresult GetSessionStorageCacheHelper(nsIPrincipal* aPrincipal,
bool aMakeIfNeeded,
SessionStorageCache* aCloneFrom,
@ -95,32 +124,58 @@ class SessionStorageManager final : public nsIDOMSessionStorageManager,
SessionStorageCache* aCloneFrom,
RefPtr<SessionStorageCache>* aRetVal);
struct OriginRecord {
OriginRecord() = default;
OriginRecord(OriginRecord&&) = default;
OriginRecord& operator=(OriginRecord&&) = default;
~OriginRecord();
RefPtr<SessionStorageCache> mCache;
nsTHashtable<nsUint64HashKey> mKnownTo;
enum ClearStorageType {
eAll,
eSessionOnly,
};
void ClearStorages(ClearStorageType aType,
const OriginAttributesPattern& aPattern,
const nsACString& aOriginScope);
OriginRecord* GetOriginRecord(const nsACString& aOriginAttrs,
const nsACString& aOriginKey,
bool aMakeIfNeeded,
SessionStorageCache* aCloneFrom);
SessionStorageCacheChild* EnsureCache(const nsCString& aOriginAttrs,
const nsCString& aOriginKey,
SessionStorageCache& aCache);
template <typename Actor>
void SendSessionStorageCache(Actor* aActor, const nsACString& aOriginAttrs,
const nsACString& aOriginKey,
SessionStorageCache* aCache);
using OriginKeyHashTable = nsClassHashtable<nsCStringHashKey, OriginRecord>;
nsClassHashtable<nsCStringHashKey, OriginKeyHashTable> mOATable;
void CheckpointDataInternal(const nsCString& aOriginAttrs,
const nsCString& aOriginKey,
SessionStorageCache& aCache);
RefPtr<SessionStorageObserver> mObserver;
RefPtr<BrowsingContext> mBrowsingContext;
SessionStorageManagerChild* mActor;
};
/**
* A specialized SessionStorageManager class that lives on the parent process
* background thread. It is a shadow copy of SessionStorageManager and it's used
* to preserve SessionStorageCaches for the other SessionStorageManagers.
*/
class BackgroundSessionStorageManager final : public SessionStorageManagerBase {
public:
// Parent process getter function.
static BackgroundSessionStorageManager* GetOrCreate(uint64_t aTopContextId);
NS_INLINE_DECL_REFCOUNTING(BackgroundSessionStorageManager);
// Only called by ~BrowsingContext on parent process.
static void RemoveManager(uint64_t aTopContextId);
void CopyDataToContentProcess(const nsACString& aOriginAttrs,
const nsACString& aOriginKey,
nsTArray<SSSetItemInfo>& aDefaultData,
nsTArray<SSSetItemInfo>& aSessionData);
void UpdateData(const nsACString& aOriginAttrs, const nsACString& aOriginKey,
const nsTArray<SSWriteInfo>& aDefaultWriteInfos,
const nsTArray<SSWriteInfo>& aSessionWriteInfos);
private:
// Only be called by GetOrCreate() on the parent process.
explicit BackgroundSessionStorageManager();
~BackgroundSessionStorageManager();
};
} // namespace dom

Просмотреть файл

@ -1,88 +0,0 @@
/* 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 "SessionStorageService.h"
#include "mozilla/Services.h"
#include "mozilla/Unused.h"
#include "nsIObserverService.h"
#include "nsXULAppAPI.h"
#include <cstring>
namespace mozilla {
namespace dom {
namespace {
const char* const kContentProcessShutdownTopic = "content-child-will-shutdown";
}
RefPtr<SessionStorageService> SessionStorageService::sService = nullptr;
bool SessionStorageService::sShutdown = false;
NS_IMPL_ISUPPORTS(SessionStorageService, nsIObserver)
SessionStorageService::SessionStorageService() {
if (const nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService()) {
Unused << observerService->AddObserver(this, kContentProcessShutdownTopic,
false);
}
}
SessionStorageService::~SessionStorageService() {
if (const nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService()) {
Unused << observerService->RemoveObserver(this,
kContentProcessShutdownTopic);
}
}
SessionStorageService* SessionStorageService::Get() {
if (sShutdown) {
return nullptr;
}
if (XRE_IsParentProcess()) {
ShutDown();
return nullptr;
}
if (!sService) {
sService = new SessionStorageService();
}
return sService;
}
NS_IMETHODIMP SessionStorageService::Observe(nsISupports* const aSubject,
const char* const aTopic,
const char16_t* const aData) {
if (std::strcmp(aTopic, kContentProcessShutdownTopic) == 0) {
ShutDown();
}
return NS_OK;
}
void SessionStorageService::RegisterSessionStorageManager(
SessionStorageManager* aManager) {
mManagers.PutEntry(aManager);
}
void SessionStorageService::UnregisterSessionStorageManager(
SessionStorageManager* aManager) {
if (const auto entry = mManagers.GetEntry(aManager)) {
mManagers.RemoveEntry(entry);
}
}
void SessionStorageService::ShutDown() {
sShutdown = true;
sService = nullptr;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -1,45 +0,0 @@
/* 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/. */
#ifndef mozilla_dom_SessionStorageService_h
#define mozilla_dom_SessionStorageService_h
#include "mozilla/UniquePtr.h"
#include "nsIObserver.h"
#include "nsISupportsImpl.h"
#include "nsPointerHashKeys.h"
#include "nsTHashtable.h"
namespace mozilla {
namespace dom {
class SessionStorageManager;
class SessionStorageService final : public nsIObserver {
public:
SessionStorageService();
static SessionStorageService* Get();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
void RegisterSessionStorageManager(SessionStorageManager* aManager);
void UnregisterSessionStorageManager(SessionStorageManager* aManager);
private:
~SessionStorageService();
static void ShutDown();
static RefPtr<SessionStorageService> sService;
static bool sShutdown;
nsTHashtable<nsPtrHashKey<SessionStorageManager>> mManagers;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_SessionStorageService_h

Просмотреть файл

@ -7,6 +7,8 @@
#include "StorageIPC.h"
#include "LocalStorageManager.h"
#include "SessionStorageManager.h"
#include "SessionStorageCache.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundParent.h"
@ -464,6 +466,75 @@ mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
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;
}
}
LocalStorageCacheParent::LocalStorageCacheParent(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
@ -1223,6 +1294,111 @@ nsresult SessionStorageObserverParent::Observe(
return NS_OK;
}
SessionStorageCacheParent::SessionStorageCacheParent(
const nsCString& aOriginAttrs, const nsCString& aOriginKey,
SessionStorageManagerParent* aActor)
: mOriginAttrs(aOriginAttrs),
mOriginKey(aOriginKey),
mManagerActor(aActor) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
}
SessionStorageCacheParent::~SessionStorageCacheParent() = default;
void SessionStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnBackgroundThread();
mManagerActor = nullptr;
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvLoad(
nsTArray<SSSetItemInfo>* aDefaultData,
nsTArray<SSSetItemInfo>* aSessionData) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
mLoadReceived.Flip();
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
MOZ_ASSERT(manager);
manager->CopyDataToContentProcess(mOriginAttrs, mOriginKey, *aDefaultData,
*aSessionData);
return IPC_OK();
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvCheckpoint(
nsTArray<SSWriteInfo>&& aDefaultWriteInfos,
nsTArray<SSWriteInfo>&& aSessionWriteInfos) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mManagerActor);
RefPtr<BackgroundSessionStorageManager> manager = mManagerActor->GetManager();
MOZ_ASSERT(manager);
manager->UpdateData(mOriginAttrs, mOriginKey, aDefaultWriteInfos,
aSessionWriteInfos);
return IPC_OK();
}
mozilla::ipc::IPCResult SessionStorageCacheParent::RecvDeleteMe() {
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)) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mBackgroundManager);
}
SessionStorageManagerParent::~SessionStorageManagerParent() = default;
void SessionStorageManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnBackgroundThread();
mBackgroundManager = nullptr;
}
already_AddRefed<PBackgroundSessionStorageCacheParent>
SessionStorageManagerParent::AllocPBackgroundSessionStorageCacheParent(
const nsCString& aOriginAttrs, const nsCString& aOriginKey) {
return MakeAndAddRef<SessionStorageCacheParent>(aOriginAttrs, aOriginKey,
this);
}
BackgroundSessionStorageManager* SessionStorageManagerParent::GetManager()
const {
return mBackgroundManager;
}
mozilla::ipc::IPCResult SessionStorageManagerParent::RecvDeleteMe() {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mBackgroundManager);
mBackgroundManager = nullptr;
IProtocol* mgr = Manager();
if (!PBackgroundSessionStorageManagerParent::Send__delete__(this)) {
return IPC_FAIL(
mgr, "Failed to delete PBackgroundSessionStorageManagerParent actor");
}
return IPC_OK();
}
/*******************************************************************************
* Exported functions
******************************************************************************/
@ -1335,5 +1511,10 @@ bool DeallocPSessionStorageObserverParent(
return true;
}
already_AddRefed<PBackgroundSessionStorageManagerParent>
AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId) {
return MakeAndAddRef<SessionStorageManagerParent>(aTopContextId);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -7,17 +7,24 @@
#ifndef mozilla_dom_StorageIPC_h
#define mozilla_dom_StorageIPC_h
#include "LocalStorageCache.h"
#include "StorageDBThread.h"
#include "StorageObserver.h"
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/FlippedOnce.h"
#include "mozilla/dom/PBackgroundLocalStorageCacheChild.h"
#include "mozilla/dom/PBackgroundLocalStorageCacheParent.h"
#include "mozilla/dom/PBackgroundSessionStorageCacheChild.h"
#include "mozilla/dom/PBackgroundSessionStorageCacheParent.h"
#include "mozilla/dom/PBackgroundSessionStorageManagerChild.h"
#include "mozilla/dom/PBackgroundSessionStorageManagerParent.h"
#include "mozilla/dom/PBackgroundStorageChild.h"
#include "mozilla/dom/PBackgroundStorageParent.h"
#include "mozilla/dom/PSessionStorageObserverChild.h"
#include "mozilla/dom/PSessionStorageObserverParent.h"
#include "StorageDBThread.h"
#include "LocalStorageCache.h"
#include "StorageObserver.h"
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "nsClassHashtable.h"
namespace mozilla {
@ -35,6 +42,11 @@ namespace dom {
class LocalStorageManager;
class PBackgroundStorageParent;
class PSessionStorageObserverParent;
class SessionStorageCache;
class SessionStorageCacheParent;
class SessionStorageManager;
class SessionStorageManagerParent;
class BackgroundSessionStorageManager;
class SessionStorageObserver;
class LocalStorageCacheChild final : public PBackgroundLocalStorageCacheChild {
@ -207,6 +219,76 @@ class SessionStorageObserverChild final : public PSessionStorageObserverChild {
const nsCString& aOriginScope) override;
};
class SessionStorageCacheChild final
: public PBackgroundSessionStorageCacheChild {
friend class PBackgroundSessionStorageCacheChild;
friend class SessionStorageCache;
friend class SessionStorageManager;
friend class mozilla::ipc::BackgroundChildImpl;
// SessionStorageManagerChild effectively owns this instance, although IPC
// handles its allocation/deallocation. When the SessionStorageManager
// destructor runs, it will invoke SendDeleteMeInternal() which will trigger
// both instances to drop their mutual references and cause IPC to destroy the
// actor after the DeleteMe round-trip.
SessionStorageCache* MOZ_NON_OWNING_REF mCache;
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageCacheChild, override)
public:
void AssertIsOnOwningThread() const {
NS_ASSERT_OWNINGTHREAD(SesionStoragManagerChild);
}
private:
// Only created by SessionStorageManager.
explicit SessionStorageCacheChild(SessionStorageCache* aCache);
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
~SessionStorageCacheChild();
// Only called by SessionStorageCache.
void SendDeleteMeInternal();
// IPDL methods are only called by IPDL.
void ActorDestroy(ActorDestroyReason aWhy) override;
};
class SessionStorageManagerChild final
: public PBackgroundSessionStorageManagerChild {
friend class PBackgroundSessionStorageManagerChild;
friend class SessionStorage;
friend class SessionStorageManager;
friend class mozilla::ipc::BackgroundChildImpl;
// SessionStorageManager effectively owns this instance, although IPC handles
// its allocation/deallocation. When the SessionStorageManager destructor
// runs, it will invoke SendDeleteMeInternal() which will trigger both
// instances to drop their mutual references and cause IPC to destroy the
// actor after the DeleteMe round-trip.
SessionStorageManager* MOZ_NON_OWNING_REF mSSManager;
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageManagerChild, override)
public:
void AssertIsOnOwningThread() const {
NS_ASSERT_OWNINGTHREAD(SesionStoragManagerChild);
}
private:
// Only created by SessionStorage.
explicit SessionStorageManagerChild(SessionStorageManager* aSSManager);
// Only destroyed by mozilla::ipc::BackgroundChildImpl.
~SessionStorageManagerChild();
// Only called by SessionStorageManager.
void SendDeleteMeInternal();
// IPDL methods are only called by IPDL.
void ActorDestroy(ActorDestroyReason aWhy) override;
};
class LocalStorageCacheParent final
: public PBackgroundLocalStorageCacheParent {
const PrincipalInfo mPrincipalInfo;
@ -418,6 +500,66 @@ class SessionStorageObserverParent final : public PSessionStorageObserverParent,
const nsACString& aOriginScope) override;
};
class SessionStorageCacheParent final
: public PBackgroundSessionStorageCacheParent {
friend class PBackgroundSessionStorageCacheParent;
const nsCString mOriginAttrs;
const nsCString mOriginKey;
RefPtr<SessionStorageManagerParent> mManagerActor;
FlippedOnce<false> mLoadReceived;
public:
SessionStorageCacheParent(const nsCString& aOriginAttrs,
const nsCString& aOriginKey,
SessionStorageManagerParent* aActor);
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageCacheParent, override)
private:
~SessionStorageCacheParent();
// IPDL methods are only called by IPDL.
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvLoad(
nsTArray<SSSetItemInfo>* aDefaultData,
nsTArray<SSSetItemInfo>* aSessionData) override;
mozilla::ipc::IPCResult RecvCheckpoint(
nsTArray<SSWriteInfo>&& aDefaultWriteInfos,
nsTArray<SSWriteInfo>&& aSessionWriteInfos) override;
mozilla::ipc::IPCResult RecvDeleteMe() override;
};
class SessionStorageManagerParent final
: public PBackgroundSessionStorageManagerParent {
friend class PBackgroundSessionStorageManagerParent;
RefPtr<BackgroundSessionStorageManager> mBackgroundManager;
public:
explicit SessionStorageManagerParent(uint64_t aTopContextId);
NS_INLINE_DECL_REFCOUNTING(mozilla::dom::SessionStorageManagerParent,
override)
already_AddRefed<PBackgroundSessionStorageCacheParent>
AllocPBackgroundSessionStorageCacheParent(
const nsCString& aOriginAttrs, const nsCString& aOriginKey) override;
BackgroundSessionStorageManager* GetManager() const;
private:
~SessionStorageManagerParent();
// IPDL methods are only called by IPDL.
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvDeleteMe() override;
};
PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId);
@ -447,6 +589,12 @@ bool RecvPSessionStorageObserverConstructor(
bool DeallocPSessionStorageObserverParent(
PSessionStorageObserverParent* aActor);
already_AddRefed<PBackgroundSessionStorageCacheParent>
AllocPBackgroundSessionStorageCacheParent(const nsCString& aOriginAttrs,
const nsCString& aOriginKey);
already_AddRefed<PBackgroundSessionStorageManagerParent>
AllocPBackgroundSessionStorageManagerParent(const uint64_t& aTopContextId);
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -30,7 +30,6 @@ UNIFIED_SOURCES += [
'SessionStorageCache.cpp',
'SessionStorageManager.cpp',
'SessionStorageObserver.cpp',
'SessionStorageService.cpp',
'Storage.cpp',
'StorageActivityService.cpp',
'StorageDBThread.cpp',
@ -43,6 +42,8 @@ UNIFIED_SOURCES += [
IPDL_SOURCES += [
'PBackgroundLocalStorageCache.ipdl',
'PBackgroundSessionStorageCache.ipdl',
'PBackgroundSessionStorageManager.ipdl',
'PBackgroundStorage.ipdl',
'PSessionStorageObserver.ipdl',
]

Просмотреть файл

@ -122,5 +122,47 @@ add_task(async function() {
);
}
);
info(`Verifying SSCache is loaded to the content process only once`);
BrowserTestUtils.loadURI(browser, URL1);
await BrowserTestUtils.browserLoaded(browser);
await SpecialPowers.spawn(
browser,
[ORIGIN1, URL1, key, value],
async (ORIGIN, iframeURL, key, value) => {
is(content.window.origin, ORIGIN, `Navigate to ${ORIGIN} as expected`);
let iframe = content.document.createElement("iframe");
iframe.src = iframeURL;
content.document.body.appendChild(iframe);
await ContentTaskUtils.waitForEvent(iframe, "load");
await content.SpecialPowers.spawn(
iframe,
[ORIGIN, key, value],
async function(ORIGIN, key, value) {
is(
content.window.origin,
ORIGIN,
`Load an iframe to ${ORIGIN} as expected`
);
let value1 = content.window.sessionStorage.getItem(key);
is(
value1,
value,
`SessionStorage for ${key} in ${content.window.origin} is ` +
`preserved.`
);
// When we are here, it means we didn't hit the assertion for
// ensuring a SSCache can only be loaded on the content process
// once.
}
);
}
);
});
});

Просмотреть файл

@ -40,6 +40,7 @@
#include "mozilla/dom/RemoteWorkerControllerParent.h"
#include "mozilla/dom/RemoteWorkerServiceParent.h"
#include "mozilla/dom/ReportingHeader.h"
#include "mozilla/dom/SessionStorageManager.h"
#include "mozilla/dom/SharedWorkerParent.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/MIDIManagerParent.h"
@ -471,6 +472,15 @@ bool BackgroundParentImpl::DeallocPBackgroundStorageParent(
return mozilla::dom::DeallocPBackgroundStorageParent(aActor);
}
already_AddRefed<BackgroundParentImpl::PBackgroundSessionStorageManagerParent>
BackgroundParentImpl::AllocPBackgroundSessionStorageManagerParent(
const uint64_t& aTopContextId) {
AssertIsInMainOrSocketProcess();
AssertIsOnBackgroundThread();
return dom::AllocPBackgroundSessionStorageManagerParent(aTopContextId);
}
already_AddRefed<PIdleSchedulerParent>
BackgroundParentImpl::AllocPIdleSchedulerParent() {
AssertIsOnBackgroundThread();
@ -1072,6 +1082,37 @@ mozilla::ipc::IPCResult BackgroundParentImpl::RecvShutdownQuotaManager() {
return IPC_OK();
}
mozilla::ipc::IPCResult
BackgroundParentImpl::RecvShutdownBackgroundSessionStorageManagers() {
AssertIsInMainOrSocketProcess();
AssertIsOnBackgroundThread();
if (BackgroundParent::IsOtherProcessActor(this)) {
return IPC_FAIL_NO_REASON(this);
}
if (!mozilla::dom::RecvShutdownBackgroundSessionStorageManagers()) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
BackgroundParentImpl::RecvRemoveBackgroundSessionStorageManager(
const uint64_t& aTopContextId) {
AssertIsInMainOrSocketProcess();
AssertIsOnBackgroundThread();
if (BackgroundParent::IsOtherProcessActor(this)) {
return IPC_FAIL_NO_REASON(this);
}
if (!mozilla::dom::RecvRemoveBackgroundSessionStorageManager(aTopContextId)) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
already_AddRefed<dom::PFileSystemRequestParent>
BackgroundParentImpl::AllocPFileSystemRequestParent(
const FileSystemParams& aParams) {

Просмотреть файл

@ -141,6 +141,10 @@ class BackgroundParentImpl : public PBackgroundParent,
virtual bool DeallocPBackgroundStorageParent(
PBackgroundStorageParent* aActor) override;
virtual already_AddRefed<PBackgroundSessionStorageManagerParent>
AllocPBackgroundSessionStorageManagerParent(
const uint64_t& aTopContextId) override;
virtual already_AddRefed<PIdleSchedulerParent> AllocPIdleSchedulerParent()
override;
@ -316,6 +320,12 @@ class BackgroundParentImpl : public PBackgroundParent,
virtual mozilla::ipc::IPCResult RecvShutdownQuotaManager() override;
virtual mozilla::ipc::IPCResult RecvShutdownBackgroundSessionStorageManagers()
override;
virtual mozilla::ipc::IPCResult RecvRemoveBackgroundSessionStorageManager(
const uint64_t& aTopContextId) override;
virtual already_AddRefed<PFileSystemRequestParent>
AllocPFileSystemRequestParent(const FileSystemParams&) override;

Просмотреть файл

@ -11,6 +11,7 @@ include protocol PBackgroundLSObserver;
include protocol PBackgroundLSRequest;
include protocol PBackgroundLSSimpleRequest;
include protocol PBackgroundLocalStorageCache;
include protocol PBackgroundSessionStorageManager;
include protocol PBackgroundStorage;
include protocol PBackgroundTest;
include protocol PBroadcastChannel;
@ -82,6 +83,7 @@ sync protocol PBackground
manages PBackgroundLSRequest;
manages PBackgroundLSSimpleRequest;
manages PBackgroundLocalStorageCache;
manages PBackgroundSessionStorageManager;
manages PBackgroundStorage;
manages PBackgroundTest;
manages PBroadcastChannel;
@ -170,6 +172,8 @@ parent:
nsCString originKey,
uint32_t privateBrowsingId);
async PBackgroundSessionStorageManager(uint64_t aTopContextId);
async PBackgroundStorage(nsString profilePath);
async PVsync();
@ -195,6 +199,10 @@ parent:
async ShutdownQuotaManager();
async ShutdownBackgroundSessionStorageManagers();
async RemoveBackgroundSessionStorageManager(uint64_t topContextId);
async PFileSystemRequest(FileSystemParams params);
async PGamepadEventChannel();

Просмотреть файл

@ -573,6 +573,10 @@ VIRTUAL_CALL_CLASSES = set([
# .h includes something that's a LOCAL_INCLUDE
("PBackgroundLocalStorageCache", "child"),
("PBackgroundLocalStorageCache", "parent"),
("PBackgroundSessionStorageCache", "child"),
("PBackgroundSessionStorageCache", "parent"),
("PBackgroundSessionStorageManager", "child"),
("PBackgroundSessionStorageManager", "parent"),
("PBackgroundStorage", "child"),
("PBackgroundStorage", "parent"),
("PBrowserStream", "parent"),

Просмотреть файл

@ -900,6 +900,8 @@ description = See corresponding comment in PBackgroundLSSnapshot.ipdl
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
[PBackgroundLSSnapshot::Ping]
description = See corresponding comment in PBackgroundLSSnapshot.ipdl
[PBackgroundSessionStorageCache::Load]
description = See corresponding comment in PBackgroundSessionStorageCache.ipdl
[PRemoteSpellcheckEngine::CheckAndSuggest]
description = legacy sync IPC - please add detailed description
[PRemoteSpellcheckEngine::SetDictionary]

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
#define LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
#include "ipc/IPCMessageUtils.h"
#include "nsIFrame.h"
#include "mozilla/AspectRatio.h"