mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Bug 1571063 - Simplify BrowsingContext field sync logic, r=farre
Differential Revision: https://phabricator.services.mozilla.com/D40524 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
52c343cca6
commit
ea27710b35
@ -852,57 +852,72 @@ void BrowsingContext::PostMessageMoz(JSContext* aCx,
|
||||
}
|
||||
|
||||
void BrowsingContext::Transaction::Commit(BrowsingContext* aBrowsingContext) {
|
||||
if (!Validate(aBrowsingContext, nullptr)) {
|
||||
MOZ_CRASH("Cannot commit invalid BrowsingContext transaction");
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
|
||||
// Increment the field epoch for fields affected by this transaction. We
|
||||
// only need to do this in content.
|
||||
#define MOZ_BC_FIELD_RACY(name, ...) \
|
||||
if (m##name) { \
|
||||
aBrowsingContext->mFieldEpochs.m##name++; \
|
||||
uint64_t epoch = cc->NextBrowsingContextFieldEpoch();
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name) { \
|
||||
aBrowsingContext->mEpochs.name = epoch; \
|
||||
}
|
||||
#define MOZ_BC_FIELD(...) /* nothing */
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
cc->SendCommitBrowsingContextTransaction(aBrowsingContext, *this,
|
||||
aBrowsingContext->mFieldEpochs);
|
||||
cc->SendCommitBrowsingContextTransaction(aBrowsingContext, *this, epoch);
|
||||
} else {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
aBrowsingContext->Group()->EachParent([&](ContentParent* aParent) {
|
||||
const FieldEpochs& childEpochs =
|
||||
aBrowsingContext->Canonical()->GetFieldEpochsForChild(aParent);
|
||||
Unused << aParent->SendCommitBrowsingContextTransaction(
|
||||
aBrowsingContext, *this, childEpochs);
|
||||
aBrowsingContext, *this, aParent->GetBrowsingContextFieldEpoch());
|
||||
});
|
||||
}
|
||||
|
||||
Apply(aBrowsingContext, nullptr);
|
||||
Apply(aBrowsingContext);
|
||||
}
|
||||
bool BrowsingContext::Transaction::Validate(BrowsingContext* aBrowsingContext,
|
||||
ContentParent* aSource) {
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name && !aBrowsingContext->MaySet##name(*m##name, aSource)) { \
|
||||
NS_WARNING("Invalid attempt to set BC field " #name); \
|
||||
return false; \
|
||||
}
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
|
||||
mValidated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BrowsingContext::Transaction::Apply(BrowsingContext* aBrowsingContext,
|
||||
ContentParent* aSource,
|
||||
const FieldEpochs* aEpochs) {
|
||||
// Filter out racy fields which have been updated in this process since this
|
||||
// transaction was committed in the parent. This should only ever occur in the
|
||||
// content process.
|
||||
if (aEpochs) {
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
#define MOZ_BC_FIELD_RACY(name, ...) \
|
||||
if (m##name) { \
|
||||
if (aEpochs->m##name < aBrowsingContext->mFieldEpochs.m##name) { \
|
||||
m##name.reset(); \
|
||||
} \
|
||||
}
|
||||
#define MOZ_BC_FIELD(...) /* nothing */
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
}
|
||||
bool BrowsingContext::Transaction::Validate(BrowsingContext* aBrowsingContext,
|
||||
ContentParent* aSource,
|
||||
uint64_t aEpoch) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(),
|
||||
"Should only be called in content process");
|
||||
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name) { \
|
||||
aBrowsingContext->WillSet##name(*m##name, aSource); \
|
||||
aBrowsingContext->m##name = std::move(*m##name); \
|
||||
aBrowsingContext->DidSet##name(aSource); \
|
||||
m##name.reset(); \
|
||||
// Clear fields which are obsoleted by the epoch.
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name && aBrowsingContext->mEpochs.name < aEpoch) { \
|
||||
m##name.reset(); \
|
||||
}
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
|
||||
return Validate(aBrowsingContext, aSource);
|
||||
}
|
||||
|
||||
void BrowsingContext::Transaction::Apply(BrowsingContext* aBrowsingContext) {
|
||||
MOZ_RELEASE_ASSERT(mValidated,
|
||||
"Must validate BrowsingContext Transaction before Apply");
|
||||
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name) { \
|
||||
aBrowsingContext->m##name = std::move(*m##name); \
|
||||
aBrowsingContext->DidSet##name(); \
|
||||
m##name.reset(); \
|
||||
}
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
}
|
||||
@ -969,7 +984,7 @@ void BrowsingContext::StartDelayedAutoplayMediaComponents() {
|
||||
mDocShell->StartDelayedAutoplayMediaComponents();
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSetIsActivatedByUserGesture(ContentParent* aSource) {
|
||||
void BrowsingContext::DidSetIsActivatedByUserGesture() {
|
||||
MOZ_ASSERT(!mParent, "Set user activation flag on non top-level context!");
|
||||
USER_ACTIVATION_LOG(
|
||||
"Set user gesture activation %d for %s browsing context 0x%08" PRIx64,
|
||||
@ -1044,6 +1059,10 @@ bool IPDLParamTraits<dom::BrowsingContext*>::Read(
|
||||
void IPDLParamTraits<dom::BrowsingContext::Transaction>::Write(
|
||||
IPC::Message* aMessage, IProtocol* aActor,
|
||||
const dom::BrowsingContext::Transaction& aTransaction) {
|
||||
MOZ_RELEASE_ASSERT(
|
||||
aTransaction.mValidated,
|
||||
"Must validate BrowsingContext Transaction before sending");
|
||||
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
WriteIPDLParam(aMessage, aActor, aTransaction.m##name);
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
@ -1052,6 +1071,8 @@ void IPDLParamTraits<dom::BrowsingContext::Transaction>::Write(
|
||||
bool IPDLParamTraits<dom::BrowsingContext::Transaction>::Read(
|
||||
const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
|
||||
dom::BrowsingContext::Transaction* aTransaction) {
|
||||
aTransaction->mValidated = false;
|
||||
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aTransaction->m##name)) { \
|
||||
return false; \
|
||||
@ -1061,27 +1082,6 @@ bool IPDLParamTraits<dom::BrowsingContext::Transaction>::Read(
|
||||
return true;
|
||||
}
|
||||
|
||||
void IPDLParamTraits<dom::BrowsingContext::FieldEpochs>::Write(
|
||||
IPC::Message* aMessage, IProtocol* aActor,
|
||||
const dom::BrowsingContext::FieldEpochs& aEpochs) {
|
||||
#define MOZ_BC_FIELD_RACY(name, ...) \
|
||||
WriteIPDLParam(aMessage, aActor, aEpochs.m##name);
|
||||
#define MOZ_BC_FIELD(...) /* nothing */
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
}
|
||||
|
||||
bool IPDLParamTraits<dom::BrowsingContext::FieldEpochs>::Read(
|
||||
const IPC::Message* aMessage, PickleIterator* aIterator, IProtocol* aActor,
|
||||
dom::BrowsingContext::FieldEpochs* aEpochs) {
|
||||
#define MOZ_BC_FIELD_RACY(name, ...) \
|
||||
if (!ReadIPDLParam(aMessage, aIterator, aActor, &aEpochs->m##name)) { \
|
||||
return false; \
|
||||
}
|
||||
#define MOZ_BC_FIELD(...) /* nothing */
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
return true;
|
||||
}
|
||||
|
||||
void IPDLParamTraits<dom::BrowsingContext::IPCInitializer>::Write(
|
||||
IPC::Message* aMessage, IProtocol* aActor,
|
||||
const dom::BrowsingContext::IPCInitializer& aInit) {
|
||||
|
@ -68,8 +68,10 @@ class BrowsingContextBase {
|
||||
type m##name; \
|
||||
\
|
||||
/* shadow to validate fields. aSource is setter process or null*/ \
|
||||
void WillSet##name(type const& aValue, ContentParent* aSource) {} \
|
||||
void DidSet##name(ContentParent* aSource) {}
|
||||
bool MaySet##name(type const& aValue, ContentParent* aSource) { \
|
||||
return true; \
|
||||
} \
|
||||
void DidSet##name() {}
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
};
|
||||
|
||||
@ -291,17 +293,6 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
|
||||
|
||||
void StartDelayedAutoplayMediaComponents();
|
||||
|
||||
/**
|
||||
* Each synced racy field in a BrowsingContext needs to have a epoch value
|
||||
* which is used to resolve race conflicts by ensuring that only the last
|
||||
* message received in the parent process wins.
|
||||
*/
|
||||
struct FieldEpochs {
|
||||
#define MOZ_BC_FIELD(...) /* nothing */
|
||||
#define MOZ_BC_FIELD_RACY(name, ...) uint64_t m##name = 0;
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
};
|
||||
|
||||
/**
|
||||
* Transaction object. This object is used to specify and then commit
|
||||
* modifications to synchronized fields in BrowsingContexts.
|
||||
@ -309,36 +300,36 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
|
||||
class Transaction {
|
||||
public:
|
||||
// Apply the changes from this transaction to the specified BrowsingContext
|
||||
// in all processes. This method will call the correct `WillSet` and
|
||||
// in all processes. This method will call the correct `MaySet` and
|
||||
// `DidSet` methods, as well as move the value.
|
||||
//
|
||||
// NOTE: This method mutates `this`, resetting all members to `Nothing()`
|
||||
void Commit(BrowsingContext* aOwner);
|
||||
|
||||
// You probably don't want to directly call this method - instead call
|
||||
// `Commit`, which will perform the necessary synchronization.
|
||||
// This method should be called before invoking `Apply` on this transaction
|
||||
// object.
|
||||
//
|
||||
// |aSource| is the ContentParent which is performing the mutation in the
|
||||
// parent process.
|
||||
void Apply(BrowsingContext* aOwner, ContentParent* aSource,
|
||||
const FieldEpochs* aEpochs = nullptr);
|
||||
MOZ_MUST_USE bool Validate(BrowsingContext* aOwner, ContentParent* aSource,
|
||||
uint64_t aEpoch);
|
||||
MOZ_MUST_USE bool Validate(BrowsingContext* aOwner, ContentParent* aSource);
|
||||
|
||||
bool HasNonRacyField() const {
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (m##name.isSome()) { \
|
||||
return true; \
|
||||
}
|
||||
#define MOZ_BC_FIELD_RACY(...) /* nothing */
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
|
||||
return false;
|
||||
}
|
||||
// You probably don't want to directly call this method - instead call
|
||||
// `Commit`, which will perform the necessary synchronization.
|
||||
//
|
||||
// `Validate` must be called before calling this method.
|
||||
void Apply(BrowsingContext* aOwner);
|
||||
|
||||
#define MOZ_BC_FIELD(name, type) mozilla::Maybe<type> m##name;
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
|
||||
private:
|
||||
friend struct mozilla::ipc::IPDLParamTraits<Transaction>;
|
||||
|
||||
// Has `Validate` been called on this method yet?
|
||||
// NOTE: This field is not synced, and must be called in every process.
|
||||
bool mValidated = false;
|
||||
};
|
||||
|
||||
#define MOZ_BC_FIELD(name, type) \
|
||||
@ -449,15 +440,16 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
|
||||
};
|
||||
|
||||
// Ensure that opener is in the same BrowsingContextGroup.
|
||||
void WillSetOpener(const uint64_t& aValue, ContentParent* aSource) {
|
||||
bool MaySetOpener(const uint64_t& aValue, ContentParent* aSource) {
|
||||
if (aValue != 0) {
|
||||
RefPtr<BrowsingContext> opener = Get(aValue);
|
||||
MOZ_RELEASE_ASSERT(opener && opener->Group() == Group());
|
||||
return opener && opener->Group() == Group();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure that we only set the flag on the top level browsing context.
|
||||
void DidSetIsActivatedByUserGesture(ContentParent* aSource);
|
||||
void DidSetIsActivatedByUserGesture();
|
||||
|
||||
// Type of BrowsingContent
|
||||
const Type mType;
|
||||
@ -479,7 +471,17 @@ class BrowsingContext : public nsWrapperCache, public BrowsingContextBase {
|
||||
JS::Heap<JSObject*> mWindowProxy;
|
||||
LocationProxy mLocation;
|
||||
|
||||
FieldEpochs mFieldEpochs;
|
||||
// Whenever a `Transaction` is committed, it is associated with a new
|
||||
// "Browsing Context Epoch". The epoch is associated with a specific content
|
||||
// process. This `mEpochs` field tracks the epoch of the most recent comitted
|
||||
// transaction in this process, and is used to resolve races between processes
|
||||
// and ensure browsing context field consistency.
|
||||
//
|
||||
// This field is only used by content processes.
|
||||
struct {
|
||||
#define MOZ_BC_FIELD(name, ...) uint64_t name;
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
} mEpochs;
|
||||
|
||||
// Is the most recent Document in this BrowsingContext loaded within this
|
||||
// process? This may be true with a null mDocShell after the Window has been
|
||||
@ -509,7 +511,6 @@ extern bool GetRemoteOuterWindowProxy(JSContext* aCx, BrowsingContext* aContext,
|
||||
JS::MutableHandle<JSObject*> aRetVal);
|
||||
|
||||
typedef BrowsingContext::Transaction BrowsingContextTransaction;
|
||||
typedef BrowsingContext::FieldEpochs BrowsingContextFieldEpochs;
|
||||
typedef BrowsingContext::IPCInitializer BrowsingContextInitializer;
|
||||
typedef BrowsingContext::Children BrowsingContextChildren;
|
||||
|
||||
@ -535,16 +536,6 @@ struct IPDLParamTraits<dom::BrowsingContext::Transaction> {
|
||||
dom::BrowsingContext::Transaction* aTransaction);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<dom::BrowsingContext::FieldEpochs> {
|
||||
static void Write(IPC::Message* aMessage, IProtocol* aActor,
|
||||
const dom::BrowsingContext::FieldEpochs& aEpochs);
|
||||
|
||||
static bool Read(const IPC::Message* aMessage, PickleIterator* aIterator,
|
||||
IProtocol* aActor,
|
||||
dom::BrowsingContext::FieldEpochs* aEpochs);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IPDLParamTraits<dom::BrowsingContext::IPCInitializer> {
|
||||
static void Write(IPC::Message* aMessage, IProtocol* aActor,
|
||||
|
@ -4,18 +4,14 @@
|
||||
* 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/. */
|
||||
|
||||
// By defualt, synced fields may only be set by the currently active process,
|
||||
// however a field can be marked as `MOZ_BC_FIELD_RACY` to relax this
|
||||
// restriction, and allow it to be set from any process.
|
||||
// Fields are, by default, settable by any process and readable by any process.
|
||||
// Racy sets will be resolved as-if they occurred in the order the parent
|
||||
// process finds out about them.
|
||||
//
|
||||
// Process restrictions on racy fields may be added in `WillSet{name}`
|
||||
// validators.
|
||||
#ifndef MOZ_BC_FIELD_RACY
|
||||
# define MOZ_BC_FIELD_RACY MOZ_BC_FIELD
|
||||
#endif
|
||||
|
||||
MOZ_BC_FIELD_RACY(Name, nsString)
|
||||
MOZ_BC_FIELD_RACY(Closed, bool)
|
||||
// Process restrictions may be added by declaring a method `MaySet{name}` on
|
||||
// `BrowsingContext`.
|
||||
MOZ_BC_FIELD(Name, nsString)
|
||||
MOZ_BC_FIELD(Closed, bool)
|
||||
MOZ_BC_FIELD(CrossOriginPolicy, nsILoadInfo::CrossOriginPolicy)
|
||||
MOZ_BC_FIELD(InheritedCrossOriginPolicy, nsILoadInfo::CrossOriginPolicy)
|
||||
MOZ_BC_FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy)
|
||||
@ -26,7 +22,6 @@ MOZ_BC_FIELD(OpenerId, uint64_t)
|
||||
|
||||
// Toplevel browsing contexts only. This field controls whether the browsing
|
||||
// context is currently considered to be activated by a gesture.
|
||||
MOZ_BC_FIELD_RACY(IsActivatedByUserGesture, bool)
|
||||
MOZ_BC_FIELD(IsActivatedByUserGesture, bool)
|
||||
|
||||
#undef MOZ_BC_FIELD
|
||||
#undef MOZ_BC_FIELD_RACY
|
||||
|
@ -136,31 +136,6 @@ void CanonicalBrowsingContext::SetEmbedderWindowGlobal(
|
||||
mEmbedderWindowGlobal = aGlobal;
|
||||
}
|
||||
|
||||
bool CanonicalBrowsingContext::ValidateTransaction(
|
||||
const Transaction& aTransaction, ContentParent* aProcess) {
|
||||
if (MOZ_LOG_TEST(GetLog(), LogLevel::Debug)) {
|
||||
#define MOZ_BC_FIELD(name, ...) \
|
||||
if (aTransaction.m##name.isSome()) { \
|
||||
MOZ_LOG(GetLog(), LogLevel::Debug, \
|
||||
("Validate Transaction 0x%08" PRIx64 " set " #name \
|
||||
" (from: 0x%08" PRIx64 " owner: 0x%08" PRIx64 ")", \
|
||||
Id(), aProcess ? static_cast<uint64_t>(aProcess->ChildID()) : 0, \
|
||||
mProcessId)); \
|
||||
}
|
||||
#include "mozilla/dom/BrowsingContextFieldList.h"
|
||||
}
|
||||
|
||||
// Check that the correct process is performing sets for transactions with
|
||||
// non-racy fields.
|
||||
if (aTransaction.HasNonRacyField()) {
|
||||
if (NS_WARN_IF(aProcess && mProcessId != aProcess->ChildID())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject* CanonicalBrowsingContext::WrapObject(
|
||||
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
|
||||
return CanonicalBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
|
||||
@ -209,20 +184,5 @@ void CanonicalBrowsingContext::NotifyMediaMutedChanged(bool aMuted) {
|
||||
});
|
||||
}
|
||||
|
||||
void CanonicalBrowsingContext::SetFieldEpochsForChild(
|
||||
ContentParent* aChild, const BrowsingContext::FieldEpochs& aEpochs) {
|
||||
mChildFieldEpochs.Put(aChild->ChildID(), aEpochs);
|
||||
}
|
||||
|
||||
const BrowsingContext::FieldEpochs&
|
||||
CanonicalBrowsingContext::GetFieldEpochsForChild(ContentParent* aChild) {
|
||||
static const BrowsingContext::FieldEpochs sDefaultFieldEpochs;
|
||||
|
||||
if (auto entry = mChildFieldEpochs.Lookup(aChild->ChildID())) {
|
||||
return entry.Data();
|
||||
}
|
||||
return sDefaultFieldEpochs;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -78,15 +78,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||
// other top level windows in other processes.
|
||||
void NotifyMediaMutedChanged(bool aMuted);
|
||||
|
||||
// Validate that the given process is allowed to perform the given
|
||||
// transaction. aSource is |nullptr| if set in the parent process.
|
||||
bool ValidateTransaction(const Transaction& aTransaction,
|
||||
ContentParent* aSource);
|
||||
|
||||
void SetFieldEpochsForChild(ContentParent* aChild,
|
||||
const FieldEpochs& aEpochs);
|
||||
const FieldEpochs& GetFieldEpochsForChild(ContentParent* aChild);
|
||||
|
||||
protected:
|
||||
void Traverse(nsCycleCollectionTraversalCallback& cb);
|
||||
void Unlink();
|
||||
@ -108,10 +99,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
||||
nsTHashtable<nsRefPtrHashKey<WindowGlobalParent>> mWindowGlobals;
|
||||
RefPtr<WindowGlobalParent> mCurrentWindowGlobal;
|
||||
RefPtr<WindowGlobalParent> mEmbedderWindowGlobal;
|
||||
|
||||
// Generation information for each content process which has interacted with
|
||||
// this CanonicalBrowsingContext, by ChildID.
|
||||
nsDataHashtable<nsUint64HashKey, FieldEpochs> mChildFieldEpochs;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -4045,10 +4045,18 @@ mozilla::ipc::IPCResult ContentChild::RecvWindowPostMessage(
|
||||
|
||||
mozilla::ipc::IPCResult ContentChild::RecvCommitBrowsingContextTransaction(
|
||||
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
|
||||
BrowsingContext::FieldEpochs&& aEpochs) {
|
||||
if (aContext) {
|
||||
aTransaction.Apply(aContext, nullptr, &aEpochs);
|
||||
uint64_t aEpoch) {
|
||||
if (!aContext || aContext->IsDiscarded()) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
|
||||
("ChildIPC: Trying to send a message to dead or detached context"));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (!aTransaction.Validate(aContext, nullptr, aEpoch)) {
|
||||
return IPC_FAIL(this, "Invalid BrowsingContext transaction from Parent");
|
||||
}
|
||||
|
||||
aTransaction.Apply(aContext);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -696,6 +696,15 @@ class ContentChild final : public PContentChild,
|
||||
void HoldBrowsingContextGroup(BrowsingContextGroup* aBCG);
|
||||
void ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG);
|
||||
|
||||
// See `BrowsingContext::mEpochs` for an explanation of this field.
|
||||
uint64_t GetBrowsingContextFieldEpoch() const {
|
||||
return mBrowsingContextFieldEpoch;
|
||||
}
|
||||
uint64_t NextBrowsingContextFieldEpoch() {
|
||||
mBrowsingContextFieldEpoch++;
|
||||
return mBrowsingContextFieldEpoch;
|
||||
}
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Fetch the current number of pending input events.
|
||||
//
|
||||
@ -747,7 +756,7 @@ class ContentChild final : public PContentChild,
|
||||
|
||||
mozilla::ipc::IPCResult RecvCommitBrowsingContextTransaction(
|
||||
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
|
||||
BrowsingContext::FieldEpochs&& aEpochs);
|
||||
uint64_t aEpoch);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
virtual PContentChild::Result OnMessageReceived(const Message& aMsg) override;
|
||||
@ -839,6 +848,9 @@ class ContentChild final : public PContentChild,
|
||||
|
||||
nsTArray<RefPtr<BrowsingContextGroup>> mBrowsingContextGroupHolder;
|
||||
|
||||
// See `BrowsingContext::mEpochs` for an explanation of this field.
|
||||
uint64_t mBrowsingContextFieldEpoch = 0;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
|
||||
};
|
||||
|
||||
|
@ -6060,29 +6060,33 @@ void ContentParent::OnBrowsingContextGroupUnsubscribe(
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvCommitBrowsingContextTransaction(
|
||||
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
|
||||
BrowsingContext::FieldEpochs&& aEpochs) {
|
||||
uint64_t aEpoch) {
|
||||
// Record the new BrowsingContextFieldEpoch associated with this transaction.
|
||||
// This should be done unconditionally, so that we're always in-sync.
|
||||
//
|
||||
// The order the parent process receives transactions is considered the
|
||||
// "canonical" ordering, so we don't need to worry about doing any
|
||||
// epoch-related validation.
|
||||
MOZ_ASSERT(aEpoch == mBrowsingContextFieldEpoch + 1,
|
||||
"Child process skipped an epoch?");
|
||||
mBrowsingContextFieldEpoch = aEpoch;
|
||||
|
||||
if (!aContext || aContext->IsDiscarded()) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
|
||||
("ParentIPC: Trying to run transaction on missing context."));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Check if the transaction is valid.
|
||||
if (!aContext->Canonical()->ValidateTransaction(aTransaction, this)) {
|
||||
MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Error,
|
||||
("ParentIPC: Trying to run invalid transaction."));
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
if (!aTransaction.Validate(aContext, this)) {
|
||||
return IPC_FAIL(this, "Invalid BrowsingContext transaction from Child");
|
||||
}
|
||||
|
||||
aContext->Group()->EachOtherParent(this, [&](ContentParent* aParent) {
|
||||
Unused << aParent->SendCommitBrowsingContextTransaction(
|
||||
aContext, aTransaction,
|
||||
aContext->Canonical()->GetFieldEpochsForChild(aParent));
|
||||
aContext, aTransaction, aParent->GetBrowsingContextFieldEpoch());
|
||||
});
|
||||
|
||||
aTransaction.Apply(aContext, this);
|
||||
aContext->Canonical()->SetFieldEpochsForChild(this, aEpochs);
|
||||
|
||||
aTransaction.Apply(aContext);
|
||||
return IPC_OK();
|
||||
}
|
||||
} // namespace dom
|
||||
|
@ -1058,7 +1058,7 @@ class ContentParent final : public PContentParent,
|
||||
|
||||
mozilla::ipc::IPCResult RecvCommitBrowsingContextTransaction(
|
||||
BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
|
||||
BrowsingContext::FieldEpochs&& aEpochs);
|
||||
uint64_t aEpoch);
|
||||
|
||||
mozilla::ipc::IPCResult RecvFirstIdle();
|
||||
|
||||
@ -1218,6 +1218,11 @@ class ContentParent final : public PContentParent,
|
||||
void OnBrowsingContextGroupSubscribe(BrowsingContextGroup* aGroup);
|
||||
void OnBrowsingContextGroupUnsubscribe(BrowsingContextGroup* aGroup);
|
||||
|
||||
// See `BrowsingContext::mEpochs` for an explanation of this field.
|
||||
uint64_t GetBrowsingContextFieldEpoch() const {
|
||||
return mBrowsingContextFieldEpoch;
|
||||
}
|
||||
|
||||
void UpdateNetworkLinkType();
|
||||
|
||||
static bool ShouldSyncPreference(const char16_t* aData);
|
||||
@ -1360,6 +1365,9 @@ class ContentParent final : public PContentParent,
|
||||
#endif
|
||||
|
||||
nsTHashtable<nsRefPtrHashKey<BrowsingContextGroup>> mGroups;
|
||||
|
||||
// See `BrowsingContext::mEpochs` for an explanation of this field.
|
||||
uint64_t mBrowsingContextFieldEpoch = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ContentParent, NS_CONTENTPARENT_IID)
|
||||
|
@ -99,7 +99,6 @@ using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
|
||||
using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
|
||||
using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
|
||||
using mozilla::dom::BrowsingContextTransaction from "mozilla/dom/BrowsingContext.h";
|
||||
using mozilla::dom::BrowsingContextFieldEpochs from "mozilla/dom/BrowsingContext.h";
|
||||
using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext.h";
|
||||
using base::SharedMemoryHandle from "base/shared_memory.h";
|
||||
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
|
||||
@ -1390,7 +1389,7 @@ parent:
|
||||
both:
|
||||
async CommitBrowsingContextTransaction(BrowsingContext aContext,
|
||||
BrowsingContextTransaction aTransaction,
|
||||
BrowsingContextFieldEpochs aEpochs);
|
||||
uint64_t aEpoch);
|
||||
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
Principal aPrincipal, ClonedMessageData aData);
|
||||
|
Loading…
Reference in New Issue
Block a user