Backed out 4 changesets (bug 1530550, bug 1529684) for bc crashes at [@ mozilla::dom::BrowsingContext::Detach(bool)]. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 05 Mar 2019 23:11:48 +0200
changeset 462446 1b825b6f386925ae7cbd762f6dd78a693a77a7cc
parent 462445 be4b780a7783cdf7d3ead37c98917dc0d2e94a1d
child 462447 ed1aa72d1ba31a43c8961272c8253a0cde4ede92
push id79654
push usercbrindusan@mozilla.com
push dateTue, 05 Mar 2019 21:12:37 +0000
treeherderautoland@1b825b6f3869 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1530550, 1529684
milestone67.0a1
backs out289c2b4126c9953fb4af4d7c085cf2dcedcc0504
9f3e65f6b1dda22a6e35db2c4c8e8b46377a9b93
257d45117af301a610832d9d4b6f43ba55ecb9c4
7f2bda80e47996b542d4c8f602f88a4af6b84f16
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 1530550, bug 1529684) for bc crashes at [@ mozilla::dom::BrowsingContext::Detach(bool)]. CLOSED TREE Backed out changeset 289c2b4126c9 (bug 1530550) Backed out changeset 9f3e65f6b1dd (bug 1529684) Backed out changeset 257d45117af3 (bug 1529684) Backed out changeset 7f2bda80e479 (bug 1529684)
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
docshell/base/BrowsingContextGroup.cpp
docshell/base/BrowsingContextGroup.h
docshell/base/CanonicalBrowsingContext.cpp
docshell/base/CanonicalBrowsingContext.h
dom/base/nsFrameLoader.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/RemoteFrameChild.cpp
dom/ipc/RemoteFrameChild.h
dom/ipc/RemoteFrameParent.cpp
dom/ipc/RemoteFrameParent.h
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
toolkit/components/browser/nsWebBrowser.cpp
toolkit/components/browser/nsWebBrowser.h
xpfe/appshell/nsAppShellService.cpp
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -53,16 +53,30 @@ static StaticAutoPtr<BrowsingContextMap<
 
 static void Register(BrowsingContext* aBrowsingContext) {
   MOZ_ALWAYS_TRUE(
       sBrowsingContexts->putNew(aBrowsingContext->Id(), aBrowsingContext));
 
   aBrowsingContext->Group()->Register(aBrowsingContext);
 }
 
+static void Sync(BrowsingContext* aBrowsingContext) {
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+
+  auto cc = ContentChild::GetSingleton();
+  MOZ_DIAGNOSTIC_ASSERT(cc);
+  RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
+  BrowsingContext* opener = aBrowsingContext->GetOpener();
+  cc->SendAttachBrowsingContext(parent, opener,
+                                BrowsingContextId(aBrowsingContext->Id()),
+                                aBrowsingContext->Name());
+}
+
 BrowsingContext* BrowsingContext::TopLevelBrowsingContext() {
   BrowsingContext* bc = this;
   while (bc->mParent) {
     bc = bc->mParent;
   }
   return bc;
 }
 
@@ -142,32 +156,32 @@ already_AddRefed<BrowsingContext> Browsi
 
     context->Group()->Subscribe(aOriginProcess);
   } else {
     context = new BrowsingContext(aParent, aOpener, aName, aId, Type::Content);
   }
 
   Register(context);
 
-  // Caller handles attaching us to the tree.
+  context->Attach();
 
   return context.forget();
 }
 
 BrowsingContext::BrowsingContext(BrowsingContext* aParent,
                                  BrowsingContext* aOpener,
                                  const nsAString& aName,
                                  uint64_t aBrowsingContextId, Type aType)
     : mName(aName),
       mClosed(false),
-      mOpener(aOpener),
-      mIsActivatedByUserGesture(false),
       mType(aType),
       mBrowsingContextId(aBrowsingContextId),
-      mParent(aParent) {
+      mParent(aParent),
+      mOpener(aOpener),
+      mIsActivatedByUserGesture(false) {
   // Specify our group in our constructor. We will explicitly join the group
   // when we are registered, as doing so will take a reference.
   if (mParent) {
     mGroup = mParent->Group();
   } else if (mOpener) {
     mGroup = mOpener->Group();
   } else {
     // To ensure the group has a unique ID, we will use our ID, as the founder
@@ -178,40 +192,34 @@ BrowsingContext::BrowsingContext(Browsin
 
 void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
   // XXX(nika): We should communicate that we are now an active BrowsingContext
   // process to the parent & do other validation here.
   MOZ_RELEASE_ASSERT(nsDocShell::Cast(aDocShell)->GetBrowsingContext() == this);
   mDocShell = aDocShell;
 }
 
-void BrowsingContext::Attach(bool aFromIPC) {
+void BrowsingContext::Attach() {
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: %s 0x%08" PRIx64 " to 0x%08" PRIx64,
            XRE_IsParentProcess() ? "Parent" : "Child",
            sCachedBrowsingContexts->has(Id()) ? "Re-connecting" : "Connecting",
            Id(), mParent ? mParent->Id() : 0));
 
   sCachedBrowsingContexts->remove(Id());
 
   auto* children = mParent ? &mParent->mChildren : &mGroup->Toplevels();
   MOZ_DIAGNOSTIC_ASSERT(!children->Contains(this));
 
   children->AppendElement(this);
 
-  // Send attach to our parent if we need to.
-  if (!aFromIPC && XRE_IsContentProcess()) {
-    auto cc = ContentChild::GetSingleton();
-    MOZ_DIAGNOSTIC_ASSERT(cc);
-    cc->SendAttachBrowsingContext(
-        mParent, mOpener, BrowsingContextId(mBrowsingContextId), Name());
-  }
+  Sync(this);
 }
 
-void BrowsingContext::Detach(bool aFromIPC) {
+void BrowsingContext::Detach() {
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: Detaching 0x%08" PRIx64 " from 0x%08" PRIx64,
            XRE_IsParentProcess() ? "Parent" : "Child", Id(),
            mParent ? mParent->Id() : 0));
 
   RefPtr<BrowsingContext> kungFuDeathGrip(this);
 
   BrowsingContextMap<RefPtr>::Ptr p;
@@ -229,57 +237,73 @@ void BrowsingContext::Detach(bool aFromI
     // order.
     MOZ_DIAGNOSTIC_ASSERT(children.IsEmpty() || children.Contains(this));
 
     children.RemoveElement(this);
   }
 
   Group()->Unregister(this);
 
-  // By definition, we no longer are the current process for this
-  // BrowsingContext - clear our now-dead nsDocShell reference.
-  mDocShell = nullptr;
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
 
-  if (!aFromIPC && XRE_IsContentProcess()) {
-    auto cc = ContentChild::GetSingleton();
-    MOZ_DIAGNOSTIC_ASSERT(cc);
-    cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
-  }
+  auto cc = ContentChild::GetSingleton();
+  MOZ_DIAGNOSTIC_ASSERT(cc);
+  cc->SendDetachBrowsingContext(this, false /* aMoveToBFCache */);
 }
 
-void BrowsingContext::CacheChildren(bool aFromIPC) {
+void BrowsingContext::CacheChildren() {
   if (mChildren.IsEmpty()) {
     return;
   }
 
   MOZ_LOG(GetLog(), LogLevel::Debug,
           ("%s: Caching children of 0x%08" PRIx64 "",
            XRE_IsParentProcess() ? "Parent" : "Child", Id()));
 
   MOZ_ALWAYS_TRUE(sCachedBrowsingContexts->reserve(mChildren.Length()));
 
   for (BrowsingContext* child : mChildren) {
     MOZ_ALWAYS_TRUE(sCachedBrowsingContexts->putNew(child->Id(), child));
   }
   mChildren.Clear();
 
-  if (!aFromIPC && XRE_IsContentProcess()) {
-    auto cc = ContentChild::GetSingleton();
-    MOZ_DIAGNOSTIC_ASSERT(cc);
-    cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
+  if (!XRE_IsContentProcess()) {
+    return;
   }
+
+  auto cc = ContentChild::GetSingleton();
+  MOZ_DIAGNOSTIC_ASSERT(cc);
+  cc->SendDetachBrowsingContext(this, true /* aMoveToBFCache */);
 }
 
 bool BrowsingContext::IsCached() { return sCachedBrowsingContexts->has(Id()); }
 
 void BrowsingContext::GetChildren(
     nsTArray<RefPtr<BrowsingContext>>& aChildren) {
   MOZ_ALWAYS_TRUE(aChildren.AppendElements(mChildren));
 }
 
+void BrowsingContext::SetOpener(BrowsingContext* aOpener) {
+  if (mOpener == aOpener) {
+    return;
+  }
+
+  mOpener = aOpener;
+
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+
+  auto cc = ContentChild::GetSingleton();
+  MOZ_DIAGNOSTIC_ASSERT(cc);
+  cc->SendSetOpenerBrowsingContext(this, aOpener);
+}
+
 // FindWithName follows the rules for choosing a browsing context,
 // with the exception of sandboxing for iframes. The implementation
 // for arbitrarily choosing between two browsing contexts with the
 // same name is as follows:
 //
 // 1) The start browsing context, i.e. 'this'
 // 2) Descendants in insertion order
 // 3) The parent
@@ -451,48 +475,74 @@ JSObject* BrowsingContext::WrapObject(JS
 
 void BrowsingContext::NotifyUserGestureActivation() {
   // We would set the user gesture activation flag on the top level browsing
   // context, which would automatically be sync to other top level browsing
   // contexts which are in the different process.
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
   USER_ACTIVATION_LOG("Get top level browsing context 0x%08" PRIx64,
                       topLevelBC->Id());
-  topLevelBC->SetIsActivatedByUserGesture(true);
+  topLevelBC->SetUserGestureActivation();
+
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+  auto cc = ContentChild::GetSingleton();
+  MOZ_ASSERT(cc);
+  cc->SendSetUserGestureActivation(topLevelBC, true);
 }
 
 void BrowsingContext::NotifyResetUserGestureActivation() {
   // We would reset the user gesture activation flag on the top level browsing
   // context, which would automatically be sync to other top level browsing
   // contexts which are in the different process.
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
   USER_ACTIVATION_LOG("Get top level browsing context 0x%08" PRIx64,
                       topLevelBC->Id());
-  topLevelBC->SetIsActivatedByUserGesture(false);
+  topLevelBC->ResetUserGestureActivation();
+
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+  auto cc = ContentChild::GetSingleton();
+  MOZ_ASSERT(cc);
+  cc->SendSetUserGestureActivation(topLevelBC, false);
+}
+
+void BrowsingContext::SetUserGestureActivation() {
+  MOZ_ASSERT(!mParent, "Set user activation flag on non top-level context!");
+  USER_ACTIVATION_LOG(
+      "Set user gesture activation for browsing context 0x%08" PRIx64, Id());
+  mIsActivatedByUserGesture = true;
 }
 
 bool BrowsingContext::GetUserGestureActivation() {
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
-  return topLevelBC->GetIsActivatedByUserGesture();
+  return topLevelBC->mIsActivatedByUserGesture;
+}
+
+void BrowsingContext::ResetUserGestureActivation() {
+  MOZ_ASSERT(!mParent, "Clear user activation flag on non top-level context!");
+  USER_ACTIVATION_LOG(
+      "Reset user gesture activation for browsing context 0x%08" PRIx64, Id());
+  mIsActivatedByUserGesture = false;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mOpener,
-                                  mGroup)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent, mGroup)
   if (XRE_IsParentProcess()) {
     CanonicalBrowsingContext::Cast(tmp)->Unlink();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BrowsingContext)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell, mChildren, mParent, mOpener,
-                                    mGroup)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell, mChildren, mParent, mGroup)
   if (XRE_IsParentProcess()) {
     CanonicalBrowsingContext::Cast(tmp)->Traverse(cb);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(BrowsingContext, AddRef)
@@ -559,17 +609,17 @@ Nullable<WindowProxyHolder> BrowsingCont
   // We never return null or throw an error, but the implementation in
   // nsGlobalWindow does and we need to use the same signature.
   return WindowProxyHolder(TopLevelBrowsingContext());
 }
 
 void BrowsingContext::GetOpener(JSContext* aCx,
                                 JS::MutableHandle<JS::Value> aOpener,
                                 ErrorResult& aError) const {
-  BrowsingContext* opener = GetOpener();
+  auto* opener = GetOpener();
   if (!opener) {
     aOpener.setNull();
     return;
   }
 
   if (!ToJSValue(aCx, WindowProxyHolder(opener), aOpener)) {
     aError.NoteJSContextException(aCx);
   }
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -61,31 +61,29 @@ class WindowProxyHolder;
 // supplied name prepended with 'm'. If the field needs to be
 // initialized in the constructor, then that will have to be done
 // manually, and of course keeping the same order as below.
 //
 // At all times the last line below should be __VA_ARGS__, since that
 // acts as a sentinel for callers of MOZ_FOR_EACH_SYNCED_FIELD.
 
 // clang-format off
-#define MOZ_FOR_EACH_SYNCED_BC_FIELD(declare, ...)           \
-  declare(Name, nsString, nsAString)                         \
-  declare(Closed, bool, bool)                                \
-  declare(Opener, RefPtr<BrowsingContext>, BrowsingContext*) \
-  declare(IsActivatedByUserGesture, bool, bool)              \
+#define MOZ_FOR_EACH_SYNCED_BC_FIELD(declare, ...)        \
+  declare(Name, nsString, nsAString)                   \
+  declare(Closed, bool, bool)                          \
   __VA_ARGS__
 // clang-format on
 
 #define MOZ_SYNCED_BC_FIELD_NAME(name, ...) m##name
 #define MOZ_SYNCED_BC_FIELD_ARGUMENT(name, type, atype) \
   transaction->MOZ_SYNCED_BC_FIELD_NAME(name),
 #define MOZ_SYNCED_BC_FIELD_GETTER(name, type, atype) \
-  type const& Get##name() const { return MOZ_SYNCED_BC_FIELD_NAME(name); }
+  const type& Get##name() const { return MOZ_SYNCED_BC_FIELD_NAME(name); }
 #define MOZ_SYNCED_BC_FIELD_SETTER(name, type, atype) \
-  void Set##name(atype const& aValue) {               \
+  void Set##name(const atype& aValue) {               \
     Transaction t;                                    \
     t.MOZ_SYNCED_BC_FIELD_NAME(name).emplace(aValue); \
     t.Commit(this);                                   \
   }
 #define MOZ_SYNCED_BC_FIELD_MEMBER(name, type, atype) \
   type MOZ_SYNCED_BC_FIELD_NAME(name);
 #define MOZ_SYNCED_BC_FIELD_MAYBE_MEMBER(name, type, atype) \
   mozilla::Maybe<type> MOZ_SYNCED_BC_FIELD_NAME(name);
@@ -175,25 +173,25 @@ class BrowsingContext : public nsWrapper
   nsPIDOMWindowOuter* GetDOMWindow() const {
     return mDocShell ? mDocShell->GetWindow() : nullptr;
   }
 
   // Attach the current BrowsingContext to its parent, in both the child and the
   // parent process. BrowsingContext objects are created attached by default, so
   // this method need only be called when restoring cached BrowsingContext
   // objects.
-  void Attach(bool aFromIPC = false);
+  void Attach();
 
   // Detach the current BrowsingContext from its parent, in both the
   // child and the parent process.
-  void Detach(bool aFromIPC = false);
+  void Detach();
 
   // Remove all children from the current BrowsingContext and cache
   // them to allow them to be attached again.
-  void CacheChildren(bool aFromIPC = false);
+  void CacheChildren();
 
   // Determine if the current BrowsingContext was 'cached' by the logic in
   // CacheChildren.
   bool IsCached();
 
   const nsString& Name() const { return mName; }
   void GetName(nsAString& aName) { aName = mName; }
   bool NameEquals(const nsAString& aName) { return mName.Equals(aName); }
@@ -201,16 +199,20 @@ class BrowsingContext : public nsWrapper
   bool IsContent() const { return mType == Type::Content; }
 
   uint64_t Id() const { return mBrowsingContextId; }
 
   BrowsingContext* GetParent() { return mParent; }
 
   void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
 
+  BrowsingContext* GetOpener() const { return mOpener; }
+
+  void SetOpener(BrowsingContext* aOpener);
+
   BrowsingContextGroup* Group() { return mGroup; }
 
   // Using the rules for choosing a browsing context we try to find
   // the browsing context with the given name in the set of
   // transitively reachable browsing contexts. Performs access control
   // with regards to this.
   // See
   // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name.
@@ -234,16 +236,21 @@ class BrowsingContext : public nsWrapper
   // by user gesture, and we would set the flag in the top level browsing
   // context.
   void NotifyUserGestureActivation();
 
   // This function would be called when we want to reset the user gesture
   // activation flag of the top level browsing context.
   void NotifyResetUserGestureActivation();
 
+  // These functions would only be called in the top level browsing context.
+  // They would set/reset the user gesture activation flag.
+  void SetUserGestureActivation();
+  void ResetUserGestureActivation();
+
   // Return true if it corresponding document is activated by user gesture.
   bool GetUserGestureActivation();
 
   // Return the window proxy object that corresponds to this browsing context.
   inline JSObject* GetWindowProxy() const { return mWindowProxy; }
   // Set the window proxy object that corresponds to this browsing context.
   void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
     mWindowProxy = aWindowProxy;
@@ -354,23 +361,28 @@ class BrowsingContext : public nsWrapper
   const Type mType;
 
   // Unique id identifying BrowsingContext
   const uint64_t mBrowsingContextId;
 
   RefPtr<BrowsingContextGroup> mGroup;
   RefPtr<BrowsingContext> mParent;
   Children mChildren;
+  WeakPtr<BrowsingContext> mOpener;
   nsCOMPtr<nsIDocShell> mDocShell;
   // This is not a strong reference, but using a JS::Heap for that should be
   // fine. The JSObject stored in here should be a proxy with a
   // nsOuterWindowProxy handler, which will update the pointer from its
   // objectMoved hook and clear it from its finalize hook.
   JS::Heap<JSObject*> mWindowProxy;
   LocationProxy mLocation;
+
+  // This flag is only valid in the top level browsing context, it indicates
+  // whether the corresponding document has been activated by user gesture.
+  bool mIsActivatedByUserGesture;
 };
 
 /**
  * Gets a WindowProxy object for a BrowsingContext that lives in a different
  * process (creating the object if it doesn't already exist). The WindowProxy
  * object will be in the compartment that aCx is currently in. This should only
  * be called if aContext doesn't hold a docshell, otherwise the BrowsingContext
  * lives in this process, and a same-process WindowProxy should be used (see
--- a/docshell/base/BrowsingContextGroup.cpp
+++ b/docshell/base/BrowsingContextGroup.cpp
@@ -32,39 +32,16 @@ void BrowsingContextGroup::Subscribe(Con
 }
 
 void BrowsingContextGroup::Unsubscribe(ContentParent* aOriginProcess) {
   MOZ_DIAGNOSTIC_ASSERT(aOriginProcess);
   mSubscribers.RemoveEntry(aOriginProcess);
   aOriginProcess->OnBrowsingContextGroupUnsubscribe(this);
 }
 
-void BrowsingContextGroup::EnsureSubscribed(ContentParent* aProcess) {
-  MOZ_DIAGNOSTIC_ASSERT(aProcess);
-  if (mSubscribers.Contains(aProcess)) {
-    return;
-  }
-
-  MOZ_RELEASE_ASSERT(
-      mContexts.Count() == 1,
-      "EnsureSubscribed doesn't work on non-fresh BrowsingContextGroups yet!");
-
-  // Subscribe to the BrowsingContext, and send down initial state!
-  Subscribe(aProcess);
-
-  // XXX(nika): We can't send down existing BrowsingContextGroups reliably yet
-  // due to ordering issues! (Bug ?)
-  for (auto iter = mContexts.Iter(); !iter.Done(); iter.Next()) {
-    RefPtr<BrowsingContext> bc = iter.Get()->GetKey();
-    Unused << aProcess->SendAttachBrowsingContext(
-        bc->GetParent(), bc->GetOpener(), BrowsingContextId(bc->Id()),
-        bc->Name());
-  }
-}
-
 BrowsingContextGroup::~BrowsingContextGroup() {
   for (auto iter = mSubscribers.Iter(); !iter.Done(); iter.Next()) {
     nsRefPtrHashKey<ContentParent>* entry = iter.Get();
     entry->GetKey()->OnBrowsingContextGroupUnsubscribe(this);
   }
 }
 
 nsISupports* BrowsingContextGroup::GetParentObject() const {
--- a/docshell/base/BrowsingContextGroup.h
+++ b/docshell/base/BrowsingContextGroup.h
@@ -38,19 +38,16 @@ class BrowsingContextGroup final : publi
   bool Contains(BrowsingContext* aContext);
   void Register(BrowsingContext* aContext);
   void Unregister(BrowsingContext* aContext);
 
   // Interact with the list of ContentParents
   void Subscribe(ContentParent* aOriginProcess);
   void Unsubscribe(ContentParent* aOriginProcess);
 
-  // Force the given ContentParent to subscribe to our BrowsingContextGroup.
-  void EnsureSubscribed(ContentParent* aProcess);
-
   ContentParents::Iterator ContentParentsIter() { return mSubscribers.Iter(); }
 
   // Get a reference to the list of toplevel contexts in this
   // BrowsingContextGroup.
   BrowsingContext::Children& Toplevels() { return mToplevels; }
   void GetToplevels(BrowsingContext::Children& aToplevels) {
     aToplevels.AppendElements(mToplevels);
   }
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -84,16 +84,37 @@ void CanonicalBrowsingContext::SetCurren
   mCurrentWindowGlobal = aGlobal;
 }
 
 JSObject* CanonicalBrowsingContext::WrapObject(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return CanonicalBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
 }
 
+void CanonicalBrowsingContext::NotifySetUserGestureActivationFromIPC(
+    bool aIsUserGestureActivation) {
+  if (!mCurrentWindowGlobal) {
+    return;
+  }
+
+  if (aIsUserGestureActivation) {
+    SetUserGestureActivation();
+  } else {
+    ResetUserGestureActivation();
+  }
+
+  USER_ACTIVATION_LOG("Chrome browsing context 0x%08" PRIx64
+                      " would notify other browsing contexts for updating "
+                      "user gesture activation flag.",
+                      Id());
+  // XXX(alwu) : we need to sync the flag to other browsing contexts which are
+  // not in the same child process where the flag was set. Will implement that
+  // in bug1519229.
+}
+
 void CanonicalBrowsingContext::Traverse(
     nsCycleCollectionTraversalCallback& cb) {
   CanonicalBrowsingContext* tmp = this;
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobals);
 }
 
 void CanonicalBrowsingContext::Unlink() {
   CanonicalBrowsingContext* tmp = this;
--- a/docshell/base/CanonicalBrowsingContext.h
+++ b/docshell/base/CanonicalBrowsingContext.h
@@ -30,18 +30,16 @@ class CanonicalBrowsingContext final : p
   static CanonicalBrowsingContext* Cast(BrowsingContext* aContext);
   static const CanonicalBrowsingContext* Cast(const BrowsingContext* aContext);
 
   bool IsOwnedByProcess(uint64_t aProcessId) const {
     return mProcessId == aProcessId;
   }
   uint64_t OwnerProcessId() const { return mProcessId; }
 
-  void SetOwnerProcessId(uint64_t aProcessId) { mProcessId = aProcessId; }
-
   void GetWindowGlobals(nsTArray<RefPtr<WindowGlobalParent>>& aWindows);
 
   // Called by WindowGlobalParent to register and unregister window globals.
   void RegisterWindowGlobal(WindowGlobalParent* aGlobal);
   void UnregisterWindowGlobal(WindowGlobalParent* aGlobal);
 
   // The current active WindowGlobal.
   WindowGlobalParent* GetCurrentWindowGlobal() const {
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -1843,30 +1843,16 @@ static already_AddRefed<BrowsingContext>
   }
 
   BrowsingContext::Type type = aIsContent ? BrowsingContext::Type::Content
                                           : BrowsingContext::Type::Chrome;
 
   return BrowsingContext::Create(aParentContext, aOpenerContext, aName, type);
 }
 
-static void GetFrameName(Element* aOwnerContent, nsAString& aFrameName) {
-  int32_t namespaceID = aOwnerContent->GetNameSpaceID();
-  if (namespaceID == kNameSpaceID_XHTML && !aOwnerContent->IsInHTMLDocument()) {
-    aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName);
-  } else {
-    aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, aFrameName);
-    // XXX if no NAME then use ID, after a transition period this will be
-    // changed so that XUL only uses ID too (bug 254284).
-    if (aFrameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
-      aOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, aFrameName);
-    }
-  }
-}
-
 nsresult nsFrameLoader::MaybeCreateDocShell() {
   if (mDocShell) {
     return NS_OK;
   }
   if (IsRemoteFrame()) {
     return NS_OK;
   }
   NS_ENSURE_STATE(!mDestroyCalled);
@@ -1898,17 +1884,28 @@ nsresult nsFrameLoader::MaybeCreateDocSh
     return NS_ERROR_UNEXPECTED;
   }
 
   RefPtr<BrowsingContext> parentBC = parentDocShell->GetBrowsingContext();
   MOZ_ASSERT(parentBC, "docShell must have BrowsingContext");
 
   // Determine the frame name for the new browsing context.
   nsAutoString frameName;
-  GetFrameName(mOwnerContent, frameName);
+
+  int32_t namespaceID = mOwnerContent->GetNameSpaceID();
+  if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
+    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
+  } else {
+    mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
+    // XXX if no NAME then use ID, after a transition period this will be
+    // changed so that XUL only uses ID too (bug 254284).
+    if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
+      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
+    }
+  }
 
   // Check if our new context is chrome or content
   bool isContent = parentBC->IsContent() ||
                    mOwnerContent->AttrValueIs(kNameSpaceID_None, TypeAttrName(),
                                               nsGkAtoms::content, eIgnoreCase);
 
   // Force mozbrowser frames to always be content, even if the mozbrowser
   // interfaces are disabled.
@@ -2531,27 +2528,18 @@ bool nsFrameLoader::TryRemoteBrowser() {
       Unused << window->GetNextTabParentId(&nextTabParentId);
     }
   }
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
 
   // If we're in a content process, create a RemoteFrameChild actor.
   if (XRE_IsContentProcess()) {
-    // Determine the frame name for the new browsing context.
-    nsAutoString frameName;
-    GetFrameName(mOwnerContent, frameName);
-
-    // XXX(nika): due to limitations with Browsing Context Groups and multiple
-    // processes, we can't link up aParent yet! (Bug 1532661)
-    RefPtr<BrowsingContext> browsingContext =
-        CreateBrowsingContext(nullptr, nullptr, frameName, true);
-
     mRemoteFrameChild = RemoteFrameChild::Create(
-        this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE), browsingContext);
+        this, context, NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
     return !!mRemoteFrameChild;
   }
 
   mRemoteBrowser =
       ContentParent::CreateBrowser(context, ownerElement, openerContentParent,
                                    sameTabGroupAs, nextTabParentId);
   if (!mRemoteBrowser) {
     return false;
@@ -3072,38 +3060,28 @@ already_AddRefed<mozilla::dom::Promise> 
 }
 
 already_AddRefed<nsITabParent> nsFrameLoader::GetTabParent() {
   return do_AddRef(mRemoteBrowser);
 }
 
 already_AddRefed<nsILoadContext> nsFrameLoader::LoadContext() {
   nsCOMPtr<nsILoadContext> loadContext;
-  if (IsRemoteFrame() &&
-      (mRemoteBrowser || mRemoteFrameChild || TryRemoteBrowser())) {
-    if (mRemoteBrowser) {
-      loadContext = mRemoteBrowser->GetLoadContext();
-    } else {
-      loadContext = mRemoteFrameChild->GetLoadContext();
-    }
+  if (IsRemoteFrame() && (mRemoteBrowser || TryRemoteBrowser())) {
+    loadContext = mRemoteBrowser->GetLoadContext();
   } else {
     loadContext = do_GetInterface(ToSupports(GetDocShell(IgnoreErrors())));
   }
   return loadContext.forget();
 }
 
 already_AddRefed<BrowsingContext> nsFrameLoader::GetBrowsingContext() {
   RefPtr<BrowsingContext> browsingContext;
-  if (IsRemoteFrame() &&
-      (mRemoteBrowser || mRemoteFrameChild || TryRemoteBrowser())) {
-    if (mRemoteBrowser) {
-      browsingContext = mRemoteBrowser->GetBrowsingContext();
-    } else {
-      browsingContext = mRemoteFrameChild->GetBrowsingContext();
-    }
+  if (IsRemoteFrame() && (mRemoteBrowser || TryRemoteBrowser())) {
+    browsingContext = mRemoteBrowser->GetBrowsingContext();
   } else if (GetDocShell(IgnoreErrors())) {
     browsingContext = nsDocShell::Cast(mDocShell)->GetBrowsingContext();
   }
   return browsingContext.forget();
 }
 
 void nsFrameLoader::InitializeBrowserAPI() {
   if (!OwnerIsMozBrowserFrame()) {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -907,39 +907,33 @@ nsresult ContentChild::ProvideWindowComm
   RefPtr<TabGroup> tabGroup;
   if (aTabOpener && !aForceNoOpener) {
     // The new actor will use the same tab group as the opener.
     tabGroup = aTabOpener->TabGroup();
   } else {
     tabGroup = new TabGroup();
   }
 
-  RefPtr<BrowsingContext> openerBC =
-      aParent ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()
-              : nullptr;
-  RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
-      nullptr, openerBC, aName, BrowsingContext::Type::Content);
-
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
-  RefPtr<TabChild> newChild = new TabChild(this, tabId, tabGroup, newTabContext,
-                                           browsingContext, aChromeFlags);
+  RefPtr<TabChild> newChild =
+      new TabChild(this, tabId, tabGroup, newTabContext, aChromeFlags);
 
   if (aTabOpener) {
     MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
     ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
   }
 
   nsCOMPtr<nsIEventTarget> target =
       tabGroup->EventTargetFor(TaskCategory::Other);
   SetEventTargetForActor(newChild, target);
 
   Unused << SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       RefPtr<TabChild>(newChild).forget().take(), tabId, TabId(0), *ipcContext,
-      aChromeFlags, GetID(), browsingContext, IsForBrowser());
+      aChromeFlags, GetID(), IsForBrowser());
 
   // Now that |newChild| has had its IPC link established, call |Init| to set it
   // up.
   if (NS_FAILED(newChild->Init(aParent))) {
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> parentTopInnerWindow;
@@ -1698,61 +1692,60 @@ mozilla::jsipc::PJavaScriptChild* Conten
   return NewJavaScriptChild();
 }
 
 bool ContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild) {
   ReleaseJavaScriptChild(aChild);
   return true;
 }
 
-PBrowserChild* ContentChild::AllocPBrowserChild(
-    const TabId& aTabId, const TabId& aSameTabGroupAs,
-    const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
-    const bool& aIsForBrowser) {
+PBrowserChild* ContentChild::AllocPBrowserChild(const TabId& aTabId,
+                                                const TabId& aSameTabGroupAs,
+                                                const IPCTabContext& aContext,
+                                                const uint32_t& aChromeFlags,
+                                                const ContentParentId& aCpID,
+                                                const bool& aIsForBrowser) {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason())
                  .get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
-  RefPtr<TabChild> child = TabChild::Create(
-      static_cast<ContentChild*>(this), aTabId, aSameTabGroupAs,
-      tc.GetTabContext(), aBrowsingContext, aChromeFlags);
+  RefPtr<TabChild> child =
+      TabChild::Create(static_cast<ContentChild*>(this), aTabId,
+                       aSameTabGroupAs, tc.GetTabContext(), aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool ContentChild::SendPBrowserConstructor(
     PBrowserChild* aActor, const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
-    const bool& aIsForBrowser) {
+    const ContentParentId& aCpID, const bool& aIsForBrowser) {
   if (IsShuttingDown()) {
     return false;
   }
 
   return PContentChild::SendPBrowserConstructor(aActor, aTabId, aSameTabGroupAs,
                                                 aContext, aChromeFlags, aCpID,
-                                                aBrowsingContext, aIsForBrowser);
+                                                aIsForBrowser);
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvPBrowserConstructor(
     PBrowserChild* aActor, const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
-    const bool& aIsForBrowser) {
+    const ContentParentId& aCpID, const bool& aIsForBrowser) {
   MOZ_ASSERT(!IsShuttingDown());
 
   static bool hasRunOnce = false;
   if (!hasRunOnce) {
     hasRunOnce = true;
     MOZ_ASSERT(!gFirstIdleTask);
     RefPtr<CancelableRunnable> firstIdleTask =
         NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
@@ -3681,45 +3674,16 @@ PContentChild::Result ContentChild::OnMe
     MOZ_ASSERT(!aMsg.is_reply());
 
     LSObject::OnSyncMessageHandled();
   }
 
   return result;
 }
 
-mozilla::ipc::IPCResult ContentChild::RecvAttachBrowsingContext(
-    BrowsingContext* aParent, BrowsingContext* aOpener,
-    BrowsingContextId aChildId, const nsString& aName) {
-  RefPtr<BrowsingContext> child = BrowsingContext::Get(aChildId);
-  MOZ_RELEASE_ASSERT(!child || child->IsCached());
-
-  if (!child) {
-    child = BrowsingContext::CreateFromIPC(aParent, aOpener, aName,
-                                           (uint64_t)aChildId, nullptr);
-  }
-
-  child->Attach(/* aFromIPC */ true);
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult ContentChild::RecvDetachBrowsingContext(
-    BrowsingContext* aContext, bool aMoveToBFCache) {
-  MOZ_RELEASE_ASSERT(aContext);
-
-  if (aMoveToBFCache) {
-    aContext->CacheChildren(/* aFromIPC */ true);
-  } else {
-    aContext->Detach(/* aFromIPC */ true);
-  }
-
-  return IPC_OK();
-}
-
 mozilla::ipc::IPCResult ContentChild::RecvWindowClose(BrowsingContext* aContext,
                                                       bool aTrustedCaller) {
   if (!aContext) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
             ("ChildIPC: Trying to send a message to dead or detached context"));
     return IPC_OK();
   }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -195,17 +195,16 @@ class ContentChild final : public PConte
   mozilla::ipc::IPCResult RecvSetProcessSandbox(
       const Maybe<FileDescriptor>& aBroker);
 
   PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
                                     const TabId& aSameTabGroupAs,
                                     const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
                                     const ContentParentId& aCpID,
-                                    BrowsingContext* aBrowsingContext,
                                     const bool& aIsForBrowser);
 
   bool DeallocPBrowserChild(PBrowserChild*);
 
   PIPCBlobInputStreamChild* AllocPIPCBlobInputStreamChild(
       const nsID& aID, const uint64_t& aSize);
 
   bool DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor);
@@ -513,24 +512,22 @@ class ContentChild final : public PConte
 
   bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*);
 
   bool SendPBrowserConstructor(PBrowserChild* actor, const TabId& aTabId,
                                const TabId& aSameTabGroupAs,
                                const IPCTabContext& context,
                                const uint32_t& chromeFlags,
                                const ContentParentId& aCpID,
-                               BrowsingContext* aBrowsingContext,
                                const bool& aIsForBrowser);
 
   virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(
       PBrowserChild* aCctor, const TabId& aTabId, const TabId& aSameTabGroupAs,
       const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-      const ContentParentId& aCpID, BrowsingContext* aBrowsingContext,
-      const bool& aIsForBrowser) override;
+      const ContentParentId& aCpID, const bool& aIsForBrowser) override;
 
   FORWARD_SHMEM_ALLOCATOR_TO(PContentChild)
 
   void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
   PBrowserOrId GetBrowserOrId(TabChild* aTabChild);
 
   POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
@@ -710,23 +707,16 @@ class ContentChild final : public PConte
   virtual already_AddRefed<nsIEventTarget> GetConstructedEventTarget(
       const Message& aMsg) override;
 
   virtual already_AddRefed<nsIEventTarget> GetSpecificMessageEventTarget(
       const Message& aMsg) override;
 
   virtual void OnChannelReceivedMessage(const Message& aMsg) override;
 
-  mozilla::ipc::IPCResult RecvAttachBrowsingContext(
-      BrowsingContext* aParentContext, BrowsingContext* aOpener,
-      BrowsingContextId aContextId, const nsString& aName);
-
-  mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
-                                                    bool aMoveToBFCache);
-
   mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
                                           bool aTrustedCaller);
   mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowPostMessage(
       BrowsingContext* aContext, const ClonedMessageData& aMessage,
       const PostMessageData& aData);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1120,49 +1120,36 @@ TabParent* ContentParent::CreateBrowser(
   bool isPreloadBrowser = false;
   nsAutoString isPreloadBrowserStr;
   if (aFrameElement->GetAttr(kNameSpaceID_None, nsGkAtoms::preloadedState,
                              isPreloadBrowserStr)) {
     isPreloadBrowser = isPreloadBrowserStr.EqualsLiteral("preloaded");
   }
 
   RefPtr<ContentParent> constructorSender;
-  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
-                     "Cannot allocate TabParent in content process");
+  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(), "Cannot allocate TabParent in content process");
   if (aOpenerContentParent) {
     constructorSender = aOpenerContentParent;
   } else {
     if (aContext.IsJSPlugin()) {
       constructorSender =
           GetNewOrUsedJSPluginProcess(aContext.JSPluginId(), initialPriority);
     } else {
-      constructorSender =
-          GetNewOrUsedBrowserProcess(aFrameElement, remoteType, initialPriority,
-                                     nullptr, isPreloadBrowser);
+      constructorSender = GetNewOrUsedBrowserProcess(
+          aFrameElement, remoteType, initialPriority, nullptr,
+          isPreloadBrowser);
     }
     if (!constructorSender) {
       return nullptr;
     }
   }
-
-  // FIXME: This BrowsingContext should be provided by the nsFrameLoader.
-  // (bug 1523636)
-  RefPtr<CanonicalBrowsingContext> browsingContext =
-      BrowsingContext::Create(nullptr, nullptr, EmptyString(),
-                              BrowsingContext::Type::Content)
-          .downcast<CanonicalBrowsingContext>();
-
-  // Ensure that our content process is subscribed to our newly created
-  // BrowsingContextGroup.
-  browsingContext->Group()->EnsureSubscribed(constructorSender);
-
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   cpm->RegisterRemoteFrame(tabId, ContentParentId(0), openerTabId,
-                           aContext.AsIPCTabContext(),
-                           constructorSender->ChildID());
+                            aContext.AsIPCTabContext(),
+                            constructorSender->ChildID());
 
   if (constructorSender) {
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     docShell->GetTreeOwner(getter_AddRefs(treeOwner));
     if (!treeOwner) {
       return nullptr;
     }
 
@@ -1179,27 +1166,25 @@ TabParent* ContentParent::CreateBrowser(
     }
     if (docShell->GetAffectPrivateSessionLifetime()) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
     }
 
     if (tabId == 0) {
       return nullptr;
     }
-    RefPtr<TabParent> tp = new TabParent(constructorSender, tabId, aContext,
-                                         browsingContext, chromeFlags);
-
-    browsingContext->SetOwnerProcessId(constructorSender->ChildID());
+    RefPtr<TabParent> tp(
+        new TabParent(constructorSender, tabId, aContext, chromeFlags));
 
     PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         tp.forget().take(), tabId,
         aSameTabGroupAs ? aSameTabGroupAs->GetTabId() : TabId(0),
         aContext.AsIPCTabContext(), chromeFlags, constructorSender->ChildID(),
-        browsingContext, constructorSender->IsForBrowser());
+        constructorSender->IsForBrowser());
 
     if (remoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
       // Tell the TabChild object that it was created due to a Large-Allocation
       // request.
       Unused << browser->SendAwaitLargeAlloc();
     }
 
     if (browser) {
@@ -3232,18 +3217,17 @@ bool ContentParent::CanOpenBrowser(const
   }
 
   return true;
 }
 
 PBrowserParent* ContentParent::AllocPBrowserParent(
     const TabId& aTabId, const TabId& aSameTabGroupAs,
     const IPCTabContext& aContext, const uint32_t& aChromeFlags,
-    const ContentParentId& aCpId, BrowsingContext* aBrowsingContext,
-    const bool& aIsForBrowser) {
+    const ContentParentId& aCpId, const bool& aIsForBrowser) {
   MOZ_ASSERT(!aSameTabGroupAs);
 
   Unused << aCpId;
   Unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
@@ -3291,44 +3275,36 @@ PBrowserParent* ContentParent::AllocPBro
       return nullptr;
     }
   }
 
   // And because we're allocating a remote browser, of course the
   // window is remote.
   chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
 
-  CanonicalBrowsingContext* browsingContext =
-      CanonicalBrowsingContext::Cast(aBrowsingContext);
-  if (NS_WARN_IF(!browsingContext->IsOwnedByProcess(ChildID()))) {
-    MOZ_ASSERT(false, "BrowsingContext not owned by the correct process!");
-    return nullptr;
-  }
-
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(),
-                                    browsingContext, chromeFlags);
+  TabParent* parent = new TabParent(static_cast<ContentParent*>(this), aTabId,
+                                    tc.GetTabContext(), chromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool ContentParent::DeallocPBrowserParent(PBrowserParent* frame) {
   TabParent* parent = TabParent::GetFrom(frame);
   NS_RELEASE(parent);
   return true;
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvPBrowserConstructor(
     PBrowserParent* actor, const TabId& tabId, const TabId& sameTabGroupAs,
     const IPCTabContext& context, const uint32_t& chromeFlags,
-    const ContentParentId& cpId, BrowsingContext* aBrowsingContext,
-    const bool& isForBrowser) {
+    const ContentParentId& cpId, const bool& isForBrowser) {
   TabParent* parent = TabParent::GetFrom(actor);
   // When enabling input event prioritization, input events may preempt other
   // normal priority IPC messages. To prevent the input events preempt
   // PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
   // notify parent that TabChild is created. In this case, PBrowser is initiated
   // from content so that we can set TabParent as ready to handle input events.
   parent->SetReadyToHandleInputEvents();
   return IPC_OK();
@@ -3626,18 +3602,17 @@ PChildToParentStreamParent* ContentParen
 
 bool ContentParent::DeallocPChildToParentStreamParent(
     PChildToParentStreamParent* aActor) {
   delete aActor;
   return true;
 }
 
 PParentToChildStreamParent* ContentParent::AllocPParentToChildStreamParent() {
-  MOZ_CRASH(
-      "PParentToChildStreamParent actors should be manually constructed!");
+  MOZ_CRASH("PParentToChildStreamParent actors should be manually constructed!");
 }
 
 bool ContentParent::DeallocPParentToChildStreamParent(
     PParentToChildStreamParent* aActor) {
   delete aActor;
   return true;
 }
 
@@ -5728,18 +5703,16 @@ mozilla::ipc::IPCResult ContentParent::R
     return IPC_OK();
   }
 
   if (!child) {
     child = BrowsingContext::CreateFromIPC(aParent, aOpener, aName,
                                            (uint64_t)aChildId, this);
   }
 
-  child->Attach(/* aFromIPC */ true);
-
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvDetachBrowsingContext(
     BrowsingContext* aContext, bool aMoveToBFCache) {
   if (!aContext) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
             ("ParentIPC: Trying to detach already detached"));
@@ -5756,21 +5729,61 @@ mozilla::ipc::IPCResult ContentParent::R
     // above TODO. [Bug 1471598]
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
             ("ParentIPC: Trying to detach out of process context 0x%08" PRIx64,
              aContext->Id()));
     return IPC_OK();
   }
 
   if (aMoveToBFCache) {
-    aContext->CacheChildren(/* aFromIPC */ true);
+    aContext->CacheChildren();
   } else {
-    aContext->Detach(/* aFromIPC */ true);
-  }
-
+    aContext->Detach();
+  }
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult ContentParent::RecvSetOpenerBrowsingContext(
+    BrowsingContext* aContext, BrowsingContext* aOpener) {
+  if (!aContext) {
+    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
+            ("ParentIPC: Trying to set opener already detached"));
+    return IPC_OK();
+  }
+
+  if (!aContext->Canonical()->IsOwnedByProcess(ChildID())) {
+    // Where trying to set opener on a child BrowsingContext in
+    // another child process. This is illegal since the owner of the
+    // BrowsingContext is the proccess with the in-process docshell,
+    // which is tracked by OwnerProcessId.
+
+    // TODO(farre): To crash or not to crash. Same reasoning as in
+    // above TODO. [Bug 1471598]
+    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Warning,
+            ("ParentIPC: Trying to set opener on out of process context "
+             "0x%08" PRIx64,
+             aContext->Id()));
+    return IPC_OK();
+  }
+
+  aContext->SetOpener(aOpener);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult ContentParent::RecvSetUserGestureActivation(
+    BrowsingContext* aContext, bool aNewValue) {
+  if (!aContext) {
+    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
+            ("ParentIPC: Trying to activate wrong context"));
+    return IPC_OK();
+  }
+
+  aContext->Canonical()->NotifySetUserGestureActivationFromIPC(aNewValue);
   return IPC_OK();
 }
 
 void ContentParent::RegisterRemoteWorkerActor() { ++mRemoteWorkerActors; }
 
 void ContentParent::UnregisterRemoveWorkerActor() {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -613,24 +613,30 @@ class ContentParent final : public PCont
 
   mozilla::ipc::IPCResult RecvAttachBrowsingContext(
       BrowsingContext* aParentContext, BrowsingContext* aOpener,
       BrowsingContextId aContextId, const nsString& aName);
 
   mozilla::ipc::IPCResult RecvDetachBrowsingContext(BrowsingContext* aContext,
                                                     bool aMoveToBFCache);
 
+  mozilla::ipc::IPCResult RecvSetOpenerBrowsingContext(
+      BrowsingContext* aContext, BrowsingContext* aOpener);
+
   mozilla::ipc::IPCResult RecvWindowClose(BrowsingContext* aContext,
                                           bool aTrustedCaller);
   mozilla::ipc::IPCResult RecvWindowFocus(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowBlur(BrowsingContext* aContext);
   mozilla::ipc::IPCResult RecvWindowPostMessage(
       BrowsingContext* aContext, const ClonedMessageData& aMessage,
       const PostMessageData& aData);
 
+  mozilla::ipc::IPCResult RecvSetUserGestureActivation(
+      BrowsingContext* aContext, bool aNewValue);
+
   FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
 
  protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   bool ShouldContinueFromReplyTimeout() override;
@@ -813,26 +819,24 @@ class ContentParent final : public PCont
 
   bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*);
 
   PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
                                       const TabId& aSameTabGroupAs,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
                                       const ContentParentId& aCpId,
-                                      BrowsingContext* aBrowsingContext,
                                       const bool& aIsForBrowser);
 
   bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual mozilla::ipc::IPCResult RecvPBrowserConstructor(
       PBrowserParent* actor, const TabId& tabId, const TabId& sameTabGroupAs,
       const IPCTabContext& context, const uint32_t& chromeFlags,
-      const ContentParentId& cpId, BrowsingContext* aBrowsingContext,
-      const bool& isForBrowser) override;
+      const ContentParentId& cpId, const bool& isForBrowser) override;
 
   PIPCBlobInputStreamParent* AllocPIPCBlobInputStreamParent(
       const nsID& aID, const uint64_t& aSize);
 
   bool DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor);
 
   mozilla::ipc::IPCResult RecvIsSecureURI(
       const uint32_t& aType, const URIParams& aURI, const uint32_t& aFlags,
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -173,18 +173,17 @@ parent:
      * Construct a new WindowGlobal actor for a window global in the given
      * BrowsingContext and with the given principal.
      */
     async PWindowGlobal(WindowGlobalInit init);
 
     /**
      * Construct a new Remote iframe actor.
      */
-    async PRemoteFrame(nsString aPresentationURL, nsString aRemoteType,
-                       BrowsingContext aBrowsingContext);
+    async PRemoteFrame(nsString aPresentationURL, nsString aRemoteType);
 
     /**
      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
      * widget's shareable window on the chrome side. Only used on Windows.
      */
     async SetNativeChildOfShareableWindow(uintptr_t childWindow);
 
     /**
@@ -616,16 +615,18 @@ parent:
                                      bool aHideDoorHanger);
 
     sync SetSystemFont(nsCString aFontName);
     sync GetSystemFont() returns (nsCString retval);
 
     sync SetPrefersReducedMotionOverrideForTest(bool aValue);
     sync ResetPrefersReducedMotionOverrideForTest();
 
+    async RootBrowsingContext(BrowsingContext aContext);
+
 child:
     /**
      * Notify the remote browser that it has been Show()n on this
      * side, with the given |visibleRect|.  This message is expected
      * to trigger creation of the remote browser's "widget".
      *
      * |Show()| and |Move()| take IntSizes rather than Rects because
      * content processes always render to a virtual <0, 0> top-left
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -388,18 +388,17 @@ both:
     //
     // If |sameTabGroupAs| is non-zero, the new tab should go in the same
     // TabGroup as |sameTabGroupAs|. This parameter should always be zero
     // for PBrowser messages sent from the child to the parent.
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
     async PBrowser(TabId tabId, TabId sameTabGroupAs,
                    IPCTabContext context, uint32_t chromeFlags,
-                   ContentParentId cpId, BrowsingContext browsingContext,
-                   bool isForBrowser);
+                   ContentParentId cpId, bool isForBrowser);
 
     async PFileDescriptorSet(FileDescriptor fd);
 
     // For parent->child, aBrowser must be non-null; aOuterWindowID can
     // be 0 to indicate the browser's current root document, or nonzero
     // to persist a subdocument.  For child->parent, arguments are
     // ignored and should be null/zero.
     async PWebBrowserPersistDocument(nullable PBrowser aBrowser,
@@ -1223,36 +1222,16 @@ parent:
                                                   Principal aTrackingPrincipal,
                                                   nsCString aTrackingOrigin,
                                                   nsCString aGrantedOrigin,
                                                   int aAllowMode)
           returns (bool unused);
 
     async StoreUserInteractionAsPermission(Principal aPrincipal);
 
-both:
-    async CommitBrowsingContextTransaction(BrowsingContext aContext,
-                                           BrowsingContextTransaction aTransaction);
-
-    async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
-                       Principal aPrincipal, ClonedMessageData aData);
-
-    /**
-     * Notify `push-subscription-modified` observers in the parent and child.
-     */
-    async NotifyPushSubscriptionModifiedObservers(nsCString scope,
-                                                  Principal principal);
-
-    /**
-     * Send a Push error message to all service worker clients in the parent or
-     * child.
-     */
-    async PushError(nsCString scope, Principal principal, nsString message,
-                    uint32_t flags);
-
     /**
      * Sync the BrowsingContext with id 'aContextId' and name 'aName' to the
      * parent, and attach it to the BrowsingContext 'aParentContext'. If
      * 'aParentContext' is 'nullptr' the BrowsingContext is a root in the
      * BrowsingContext tree. AttachBrowsingContext must only be called at most
      * once for any child BrowsingContext, and only for BrowsingContexts where
      * the parent and the child context contains their nsDocShell.
      */
@@ -1271,16 +1250,49 @@ both:
      * BrowsingContext belonging to an already detached subtree. The
      * 'aMoveToBFCache' paramater controls if detaching a BrowsingContext
      * should move it to the bfcache allowing it to be re-attached if navigated
      * to.
      */
     async DetachBrowsingContext(BrowsingContext aContext,
                                 bool aMoveToBFCache);
 
+    /**
+     * Set the opener of browsing context 'aContext' to the browsing context
+     * with id 'aOpenerId'.
+     */
+    async SetOpenerBrowsingContext(BrowsingContext aContext,
+                                   BrowsingContext aOpenerContext);
+
+    /**
+     * Notify parent to update user gesture activation flag.
+     */
+    async SetUserGestureActivation(BrowsingContext aContext,
+                                   bool aNewValue);
+
+both:
+    async CommitBrowsingContextTransaction(BrowsingContext aContext,
+                                           BrowsingContextTransaction aTransaction);
+
+    async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
+                       Principal aPrincipal, ClonedMessageData aData);
+
+    /**
+     * Notify `push-subscription-modified` observers in the parent and child.
+     */
+    async NotifyPushSubscriptionModifiedObservers(nsCString scope,
+                                                  Principal principal);
+
+    /**
+     * Send a Push error message to all service worker clients in the parent or
+     * child.
+     */
+    async PushError(nsCString scope, Principal principal, nsString message,
+                    uint32_t flags);
+
     async WindowClose(BrowsingContext aContext, bool aTrustedCaller);
     async WindowFocus(BrowsingContext aContext);
     async WindowBlur(BrowsingContext aContext);
     async WindowPostMessage(BrowsingContext aContext, ClonedMessageData aMessage,
                             PostMessageData aData);
 };
 
 }
--- a/dom/ipc/RemoteFrameChild.cpp
+++ b/dom/ipc/RemoteFrameChild.cpp
@@ -1,54 +1,46 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/RemoteFrameChild.h"
-#include "mozilla/dom/BrowsingContext.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
-RemoteFrameChild::RemoteFrameChild(nsFrameLoader* aFrameLoader,
-                                   BrowsingContext* aBrowsingContext)
-    : mLayersId{0},
-      mIPCOpen(true),
-      mFrameLoader(aFrameLoader),
-      mBrowsingContext(aBrowsingContext) {}
+RemoteFrameChild::RemoteFrameChild(nsFrameLoader* aFrameLoader)
+    : mLayersId{0}, mIPCOpen(true), mFrameLoader(aFrameLoader) {}
 
 RemoteFrameChild::~RemoteFrameChild() {}
 
 already_AddRefed<RemoteFrameChild> RemoteFrameChild::Create(
     nsFrameLoader* aFrameLoader, const TabContext& aContext,
-    const nsString& aRemoteType, BrowsingContext* aBrowsingContext) {
+    const nsString& aRemoteType) {
   MOZ_ASSERT(XRE_IsContentProcess());
 
   // Determine our embedder's TabChild actor.
   RefPtr<Element> owner = aFrameLoader->GetOwnerContent();
   MOZ_DIAGNOSTIC_ASSERT(owner);
 
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(owner->GetOwnerGlobal());
   MOZ_DIAGNOSTIC_ASSERT(docShell);
 
   RefPtr<TabChild> tabChild = TabChild::GetFrom(docShell);
   MOZ_DIAGNOSTIC_ASSERT(tabChild);
 
-  RefPtr<RemoteFrameChild> remoteFrame =
-      new RemoteFrameChild(aFrameLoader, aBrowsingContext);
-
+  RefPtr<RemoteFrameChild> remoteFrame = new RemoteFrameChild(aFrameLoader);
   // Reference is freed in TabChild::DeallocPRemoteFrameChild.
   tabChild->SendPRemoteFrameConstructor(
       do_AddRef(remoteFrame).take(),
-      PromiseFlatString(aContext.PresentationURL()), aRemoteType,
-      aBrowsingContext);
+      PromiseFlatString(aContext.PresentationURL()), aRemoteType);
   remoteFrame->mIPCOpen = true;
 
   return remoteFrame.forget();
 }
 
 void RemoteFrameChild::UpdateDimensions(const nsIntRect& aRect,
                                         const mozilla::ScreenIntSize& aSize) {
   MOZ_DIAGNOSTIC_ASSERT(mIPCOpen);
--- a/dom/ipc/RemoteFrameChild.h
+++ b/dom/ipc/RemoteFrameChild.h
@@ -7,59 +7,51 @@
 #ifndef mozilla_dom_RemoteFrameChild_h
 #define mozilla_dom_RemoteFrameChild_h
 
 #include "mozilla/dom/PRemoteFrameChild.h"
 #include "mozilla/dom/TabChild.h"
 
 namespace mozilla {
 namespace dom {
-class BrowsingContext;
 
 /**
  * Child side for a remote frame.
  */
 class RemoteFrameChild : public PRemoteFrameChild {
  public:
   NS_INLINE_DECL_REFCOUNTING(RemoteFrameChild);
 
   TabChild* Manager() {
     MOZ_ASSERT(mIPCOpen);
     return static_cast<TabChild*>(PRemoteFrameChild::Manager());
   }
 
   mozilla::layers::LayersId GetLayersId() { return mLayersId; }
 
-  BrowsingContext* GetBrowsingContext() { return mBrowsingContext; }
-
-  // XXX(nika): We should have a load context here. (bug 1532664)
-  nsILoadContext* GetLoadContext() { return nullptr; }
-
-  static already_AddRefed<RemoteFrameChild> Create(
-      nsFrameLoader* aFrameLoader, const TabContext& aContext,
-      const nsString& aRemoteType, BrowsingContext* aBrowsingContext);
+  static already_AddRefed<RemoteFrameChild> Create(nsFrameLoader* aFrameLoader,
+                                                   const TabContext& aContext,
+                                                   const nsString& aRemoteType);
 
   void UpdateDimensions(const nsIntRect& aRect,
                         const mozilla::ScreenIntSize& aSize);
 
  protected:
   friend class PRemoteFrameChild;
 
   mozilla::ipc::IPCResult RecvSetLayersId(
       const mozilla::layers::LayersId& aLayersId);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
-  explicit RemoteFrameChild(nsFrameLoader* aFrameLoader,
-                            BrowsingContext* aBrowsingContext);
+  explicit RemoteFrameChild(nsFrameLoader* aFrameLoader);
   ~RemoteFrameChild();
 
   mozilla::layers::LayersId mLayersId;
   bool mIPCOpen;
   RefPtr<nsFrameLoader> mFrameLoader;
-  RefPtr<BrowsingContext> mBrowsingContext;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // !defined(mozilla_dom_RemoteFrameParent_h)
--- a/dom/ipc/RemoteFrameParent.cpp
+++ b/dom/ipc/RemoteFrameParent.cpp
@@ -2,32 +2,29 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/RemoteFrameParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentProcessManager.h"
-#include "mozilla/dom/CanonicalBrowsingContext.h"
-#include "mozilla/dom/BrowsingContextGroup.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::layout;
 
 namespace mozilla {
 namespace dom {
 
 RemoteFrameParent::RemoteFrameParent() : mIPCOpen(false) {}
 
 RemoteFrameParent::~RemoteFrameParent() {}
 
 nsresult RemoteFrameParent::Init(const nsString& aPresentationURL,
-                                 const nsString& aRemoteType,
-                                 CanonicalBrowsingContext* aBrowsingContext) {
+                                 const nsString& aRemoteType) {
   mIPCOpen = true;
 
   // FIXME: This should actually use a non-bogus TabContext, probably inherited
   // from our Manager().
   OriginAttributes attrs;
   attrs.mInIsolatedMozBrowser = false;
   attrs.mAppId = nsIScriptSecurityManager::NO_APP_ID;
   attrs.SyncAttributesWithPrivateBrowsing(false);
@@ -41,36 +38,31 @@ nsresult RemoteFrameParent::Init(const n
   RefPtr<ContentParent> constructorSender =
       ContentParent::GetNewOrUsedBrowserProcess(
           nullptr, aRemoteType, initialPriority, nullptr, false);
   if (NS_WARN_IF(!constructorSender)) {
     MOZ_ASSERT(false, "Unable to allocate content process!");
     return NS_ERROR_FAILURE;
   }
 
-  // Ensure that our content process is subscribed to our newly created
-  // BrowsingContextGroup.
-  aBrowsingContext->Group()->EnsureSubscribed(constructorSender);
-  aBrowsingContext->SetOwnerProcessId(constructorSender->ChildID());
-
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   TabId tabId(nsContentUtils::GenerateTabId());
   cpm->RegisterRemoteFrame(tabId, ContentParentId(0), TabId(0),
                            tabContext.AsIPCTabContext(),
                            constructorSender->ChildID());
 
   // Construct the TabParent object for our subframe.
   uint32_t chromeFlags = 0;
-  RefPtr<TabParent> tabParent = new TabParent(
-      constructorSender, tabId, tabContext, aBrowsingContext, chromeFlags);
+  RefPtr<TabParent> tabParent(
+      new TabParent(constructorSender, tabId, tabContext, chromeFlags));
 
   PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
       // DeallocPBrowserParent() releases this ref.
       tabParent.forget().take(), tabId, TabId(0), tabContext.AsIPCTabContext(),
-      chromeFlags, constructorSender->ChildID(), aBrowsingContext,
+      chromeFlags, constructorSender->ChildID(),
       constructorSender->IsForBrowser());
   if (NS_WARN_IF(!browser)) {
     MOZ_ASSERT(false, "Browser Constructor Failed");
     return NS_ERROR_FAILURE;
   }
 
   // Set our TabParent object to the newly created browser.
   mTabParent = TabParent::GetFrom(browser);
--- a/dom/ipc/RemoteFrameParent.h
+++ b/dom/ipc/RemoteFrameParent.h
@@ -15,25 +15,20 @@ namespace dom {
 
 class RemoteFrameParent : public PRemoteFrameParent {
  public:
   NS_INLINE_DECL_REFCOUNTING(RemoteFrameParent);
 
   RemoteFrameParent();
 
   // Initialize this actor after performing startup.
-  nsresult Init(const nsString& aPresentationURL, const nsString& aRemoteType,
-                CanonicalBrowsingContext* aBrowsingContext);
+  nsresult Init(const nsString& aPresentationURL, const nsString& aRemoteType);
 
   TabParent* GetTabParent() { return mTabParent; }
 
-  CanonicalBrowsingContext* GetBrowsingContext() {
-    return mTabParent->GetBrowsingContext();
-  }
-
   // Get our manager actor.
   TabParent* Manager() {
     MOZ_ASSERT(mIPCOpen);
     return static_cast<TabParent*>(PRemoteFrameParent::Manager());
   }
 
  protected:
   friend class PRemoteFrameParent;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -349,32 +349,30 @@ already_AddRefed<TabChild> TabChild::Fin
   return tabChild.forget();
 }
 
 /*static*/
 already_AddRefed<TabChild> TabChild::Create(ContentChild* aManager,
                                             const TabId& aTabId,
                                             const TabId& aSameTabGroupAs,
                                             const TabContext& aContext,
-                                            BrowsingContext* aBrowsingContext,
                                             uint32_t aChromeFlags) {
   RefPtr<TabChild> groupChild = FindTabChild(aSameTabGroupAs);
   dom::TabGroup* group = groupChild ? groupChild->TabGroup() : nullptr;
-  RefPtr<TabChild> iframe = new TabChild(aManager, aTabId, group, aContext,
-                                         aBrowsingContext, aChromeFlags);
+  RefPtr<TabChild> iframe =
+      new TabChild(aManager, aTabId, group, aContext, aChromeFlags);
   return iframe.forget();
 }
 
 TabChild::TabChild(ContentChild* aManager, const TabId& aTabId,
                    dom::TabGroup* aTabGroup, const TabContext& aContext,
-                   BrowsingContext* aBrowsingContext, uint32_t aChromeFlags)
+                   uint32_t aChromeFlags)
     : TabContext(aContext),
       mTabGroup(aTabGroup),
       mManager(aManager),
-      mBrowsingContext(aBrowsingContext),
       mChromeFlags(aChromeFlags),
       mMaxTouchPoints(0),
       mLayersId{0},
       mBeforeUnloadListeners(0),
       mDidFakeShow(false),
       mNotified(false),
       mTriedBrowserInit(false),
       mOrientation(hal::eScreenOrientation_PortraitPrimary),
@@ -518,18 +516,19 @@ nsresult TabChild::Init(mozIDOMWindowPro
     return NS_ERROR_FAILURE;
   }
   mPuppetWidget->InfallibleCreate(nullptr,
                                   nullptr,  // no parents
                                   LayoutDeviceIntRect(0, 0, 0, 0),
                                   nullptr  // HandleWidgetEvent
   );
 
-  mWebBrowser = nsWebBrowser::Create(this, mPuppetWidget, OriginAttributesRef(),
-                                     mBrowsingContext);
+  mWebBrowser =
+      nsWebBrowser::Create(this, mPuppetWidget, OriginAttributesRef(), aParent,
+                           nsIDocShellTreeItem::typeContentWrapper);
   nsIWebBrowser* webBrowser = mWebBrowser;
 
   mWebNav = do_QueryInterface(webBrowser);
   NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   // Set the tab context attributes then pass to docShell
   NotifyTabContextUpdated(false);
 
@@ -549,16 +548,21 @@ nsresult TabChild::Init(mozIDOMWindowPro
   docShell->SetAffectPrivateSessionLifetime(
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME);
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(WebNavigation());
   MOZ_ASSERT(loadContext);
   loadContext->SetPrivateBrowsing(OriginAttributesRef().mPrivateBrowsingId > 0);
   loadContext->SetRemoteTabs(mChromeFlags &
                              nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
 
+  // Send our browsing context to the parent process.
+  RefPtr<BrowsingContext> browsingContext =
+      nsDocShell::Cast(docShell)->GetBrowsingContext();
+  SendRootBrowsingContext(browsingContext);
+
   // Few lines before, baseWindow->Create() will end up creating a new
   // window root in nsGlobalWindow::SetDocShell.
   // Then this chrome event handler, will be inherited to inner windows.
   // We want to also set it to the docshell so that inner windows
   // and any code that has access to the docshell
   // can all listen to the same chrome event handler.
   // XXX: ideally, we would set a chrome event handler earlier,
   // and all windows, even the root one, will use the docshell one.
@@ -3175,18 +3179,17 @@ PWindowGlobalChild* TabChild::AllocPWind
 
 bool TabChild::DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) {
   // This reference was added in WindowGlobalChild::Create.
   static_cast<WindowGlobalChild*>(aActor)->Release();
   return true;
 }
 
 PRemoteFrameChild* TabChild::AllocPRemoteFrameChild(const nsString&,
-                                                    const nsString&,
-                                                    BrowsingContext*) {
+                                                    const nsString&) {
   MOZ_CRASH("We should never be manually allocating PRemoteFrameChild actors");
   return nullptr;
 }
 
 bool TabChild::DeallocPRemoteFrameChild(PRemoteFrameChild* aActor) {
   // This reference was added in RemoteFrameChild::Create.
   static_cast<RemoteFrameChild*>(aActor)->Release();
   return true;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -227,27 +227,25 @@ class TabChild final : public TabChildBa
   // Return a list of all active TabChildren.
   static nsTArray<RefPtr<TabChild>> GetAll();
 
  public:
   /**
    * Create a new TabChild object.
    */
   TabChild(ContentChild* aManager, const TabId& aTabId, TabGroup* aTabGroup,
-           const TabContext& aContext, BrowsingContext* aBrowsingContext,
-           uint32_t aChromeFlags);
+           const TabContext& aContext, uint32_t aChromeFlags);
 
   nsresult Init(mozIDOMWindowProxy* aParent);
 
   /** Return a TabChild with the given attributes. */
   static already_AddRefed<TabChild> Create(ContentChild* aManager,
                                            const TabId& aTabId,
                                            const TabId& aSameTabGroupAs,
                                            const TabContext& aContext,
-                                           BrowsingContext* aBrowsingContext,
                                            uint32_t aChromeFlags);
 
   // Let managees query if it is safe to send messages.
   bool IsDestroyed() const { return mDestroyed; }
 
   const TabId GetTabId() const {
     MOZ_ASSERT(mUniqueId != 0);
     return mUniqueId;
@@ -668,18 +666,17 @@ class TabChild final : public TabChildBa
   virtual ~TabChild();
 
   virtual PWindowGlobalChild* AllocPWindowGlobalChild(
       const WindowGlobalInit& aInit) override;
 
   virtual bool DeallocPWindowGlobalChild(PWindowGlobalChild* aActor) override;
 
   virtual PRemoteFrameChild* AllocPRemoteFrameChild(
-      const nsString& aName, const nsString& aRemoteType,
-      BrowsingContext* aBrowsingContext) override;
+      const nsString& aName, const nsString& aRemoteType) override;
 
   virtual bool DeallocPRemoteFrameChild(PRemoteFrameChild* aActor) override;
 
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
 
   virtual mozilla::ipc::IPCResult RecvSetDocShellIsActive(
       const bool& aIsActive) override;
 
@@ -802,17 +799,16 @@ class TabChild final : public TabChildBa
 
   TextureFactoryIdentifier mTextureFactoryIdentifier;
   RefPtr<nsWebBrowser> mWebBrowser;
   nsCOMPtr<nsIWebNavigation> mWebNav;
   RefPtr<mozilla::dom::TabGroup> mTabGroup;
   RefPtr<PuppetWidget> mPuppetWidget;
   nsCOMPtr<nsIURI> mLastURI;
   RefPtr<ContentChild> mManager;
-  RefPtr<BrowsingContext> mBrowsingContext;
   uint32_t mChromeFlags;
   uint32_t mMaxTouchPoints;
   layers::LayersId mLayersId;
   int64_t mBeforeUnloadListeners;
   CSSRect mUnscaledOuterRect;
   Maybe<bool> mLayersConnected;
   bool mDidFakeShow;
   bool mNotified;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -139,19 +139,17 @@ namespace mozilla {
 namespace dom {
 
 TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent, nsITabParent, nsIAuthPromptProvider,
                   nsISupportsWeakReference)
 
 TabParent::TabParent(ContentParent* aManager, const TabId& aTabId,
-                     const TabContext& aContext,
-                     CanonicalBrowsingContext* aBrowsingContext,
-                     uint32_t aChromeFlags)
+                     const TabContext& aContext, uint32_t aChromeFlags)
     : TabContext(aContext),
       mFrameElement(nullptr),
       mContentCache(*this),
       mRect(0, 0, 0, 0),
       mDimensions(0, 0),
       mOrientation(0),
       mDPI(0),
       mRounding(0),
@@ -159,17 +157,16 @@ TabParent::TabParent(ContentParent* aMan
       mUpdatedDimensions(false),
       mSizeMode(nsSizeMode_Normal),
       mManager(aManager),
       mDocShellIsActive(false),
       mMarkedDestroying(false),
       mIsDestroyed(false),
       mChromeFlags(aChromeFlags),
       mDragValid(false),
-      mBrowsingContext(aBrowsingContext),
       mTabId(aTabId),
       mCreatingWindow(false),
       mCursor(eCursorInvalid),
       mCustomCursorHotspotX(0),
       mCustomCursorHotspotY(0),
       mTabSetsCursor(false),
       mHasContentOpener(false)
 #ifdef DEBUG
@@ -996,27 +993,25 @@ PWindowGlobalParent* TabParent::AllocPWi
 }
 
 bool TabParent::DeallocPWindowGlobalParent(PWindowGlobalParent* aActor) {
   // Free reference from AllocPWindowGlobalParent.
   static_cast<WindowGlobalParent*>(aActor)->Release();
   return true;
 }
 
-IPCResult TabParent::RecvPRemoteFrameConstructor(
-    PRemoteFrameParent* aActor, const nsString& aName,
-    const nsString& aRemoteType, BrowsingContext* aBrowsingContext) {
-  static_cast<RemoteFrameParent*>(aActor)->Init(
-      aName, aRemoteType, CanonicalBrowsingContext::Cast(aBrowsingContext));
+IPCResult TabParent::RecvPRemoteFrameConstructor(PRemoteFrameParent* aActor,
+                                                 const nsString& aName,
+                                                 const nsString& aRemoteType) {
+  static_cast<RemoteFrameParent*>(aActor)->Init(aName, aRemoteType);
   return IPC_OK();
 }
 
 PRemoteFrameParent* TabParent::AllocPRemoteFrameParent(
-    const nsString& aName, const nsString& aRemoteType,
-    BrowsingContext* aBrowsingContext) {
+    const nsString& aName, const nsString& aRemoteType) {
   // Reference freed in DeallocPRemoteFrameParent.
   return do_AddRef(new RemoteFrameParent()).take();
 }
 
 bool TabParent::DeallocPRemoteFrameParent(PRemoteFrameParent* aActor) {
   // Free reference from AllocPRemoteFrameParent.
   static_cast<RemoteFrameParent*>(aActor)->Release();
   return true;
@@ -3472,16 +3467,24 @@ mozilla::ipc::IPCResult TabParent::RecvS
 mozilla::ipc::IPCResult TabParent::RecvGetSystemFont(nsCString* aFontName) {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->GetSystemFont(*aFontName);
   }
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult TabParent::RecvRootBrowsingContext(
+    BrowsingContext* aBrowsingContext) {
+  MOZ_ASSERT(!mBrowsingContext, "May only set browsing context once!");
+  mBrowsingContext = CanonicalBrowsingContext::Cast(aBrowsingContext);
+  MOZ_ASSERT(mBrowsingContext, "Invalid ID!");
+  return IPC_OK();
+}
+
 NS_IMETHODIMP
 FakeChannel::OnAuthAvailable(nsISupports* aContext,
                              nsIAuthInformation* aAuthInfo) {
   nsAuthInformationHolder* holder =
       static_cast<nsAuthInformationHolder*>(aAuthInfo);
 
   if (!net::gNeckoChild->SendOnAuthAvailable(
           mCallbackId, holder->User(), holder->Password(), holder->Domain())) {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -96,18 +96,17 @@ class TabParent final : public PBrowserP
   struct AutoUseNewTab;
 
   // nsITabParent
   NS_DECL_NSITABPARENT
   // nsIDOMEventListener interfaces
   NS_DECL_NSIDOMEVENTLISTENER
 
   TabParent(ContentParent* aManager, const TabId& aTabId,
-            const TabContext& aContext,
-            CanonicalBrowsingContext* aBrowsingContext, uint32_t aChromeFlags);
+            const TabContext& aContext, uint32_t aChromeFlags);
 
   Element* GetOwnerElement() const { return mFrameElement; }
   already_AddRefed<nsPIDOMWindowOuter> GetParentWindowOuter();
 
   void SetOwnerElement(Element* aElement);
 
   void CacheFrameLoader(nsFrameLoader* aFrameLoader);
 
@@ -311,25 +310,24 @@ class TabParent final : public PBrowserP
 
   PWindowGlobalParent* AllocPWindowGlobalParent(const WindowGlobalInit& aInit);
 
   bool DeallocPWindowGlobalParent(PWindowGlobalParent* aActor);
 
   virtual mozilla::ipc::IPCResult RecvPWindowGlobalConstructor(
       PWindowGlobalParent* aActor, const WindowGlobalInit& aInit) override;
 
-  PRemoteFrameParent* AllocPRemoteFrameParent(
-      const nsString& aPresentationURL, const nsString& aRemoteType,
-      BrowsingContext* aBrowsingContext);
+  PRemoteFrameParent* AllocPRemoteFrameParent(const nsString& aPresentationURL,
+                                              const nsString& aRemoteType);
 
   bool DeallocPRemoteFrameParent(PRemoteFrameParent* aActor);
 
   virtual mozilla::ipc::IPCResult RecvPRemoteFrameConstructor(
       PRemoteFrameParent* aActor, const nsString& aPresentationURL,
-      const nsString& aRemoteType, BrowsingContext* aBrowsingContext) override;
+      const nsString& aRemoteType) override;
 
   void LoadURL(nsIURI* aURI);
 
   void InitRendering();
   void MaybeShowFrame();
 
   // XXX/cjones: it's not clear what we gain by hiding these
   // message-sending functions under a layer of indirection and
@@ -617,16 +615,18 @@ class TabParent final : public PBrowserP
                                             const int32_t& aX,
                                             const int32_t& aY,
                                             const int32_t& aCx,
                                             const int32_t& aCy);
 
   mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
       const nsCString& aFirstPartyURI, const bool& aHideDoorHanger);
 
+  mozilla::ipc::IPCResult RecvRootBrowsingContext(BrowsingContext* aContext);
+
   mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName);
   mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName);
 
   mozilla::ipc::IPCResult RecvVisitURI(const URIParams& aURI,
                                        const OptionalURIParams& aLastVisitedURI,
                                        const uint32_t& aFlags);
 
   mozilla::ipc::IPCResult RecvQueryVisitedState(
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -97,31 +97,42 @@ nsIWidget* nsWebBrowser::EnsureWidget() 
                     nullptr);
 
   return mInternalWidget;
 }
 
 /* static */
 already_AddRefed<nsWebBrowser> nsWebBrowser::Create(
     nsIWebBrowserChrome* aContainerWindow, nsIWidget* aParentWidget,
-    const OriginAttributes& aOriginAttributes,
-    dom::BrowsingContext* aBrowsingContext) {
-  RefPtr<nsWebBrowser> browser = new nsWebBrowser(
-      aBrowsingContext->IsContent() ? typeContentWrapper : typeChromeWrapper);
+    const OriginAttributes& aOriginAttributes, mozIDOMWindowProxy* aOpener,
+    int aItemType) {
+  RefPtr<nsWebBrowser> browser = new nsWebBrowser(aItemType);
 
   // nsWebBrowser::SetContainer also calls nsWebBrowser::EnsureDocShellTreeOwner
   NS_ENSURE_SUCCESS(browser->SetContainerWindow(aContainerWindow), nullptr);
   NS_ENSURE_SUCCESS(browser->SetParentWidget(aParentWidget), nullptr);
 
   nsCOMPtr<nsIWidget> docShellParentWidget = browser->EnsureWidget();
   if (NS_WARN_IF(!docShellParentWidget)) {
     return nullptr;
   }
 
-  RefPtr<nsDocShell> docShell = nsDocShell::Create(aBrowsingContext);
+  // XXX(nika): Consider supporting creating nsWebBrowser for an existing
+  // BrowsingContext (e.g. during a X-process load).
+  using BrowsingContext = mozilla::dom::BrowsingContext;
+  RefPtr<BrowsingContext> openerContext =
+      aOpener ? nsPIDOMWindowOuter::From(aOpener)->GetBrowsingContext()
+              : nullptr;
+
+  RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
+      /* aParent */ nullptr, openerContext, EmptyString(),
+      aItemType != typeChromeWrapper ? BrowsingContext::Type::Content
+                                     : BrowsingContext::Type::Chrome);
+
+  RefPtr<nsDocShell> docShell = nsDocShell::Create(browsingContext);
   if (NS_WARN_IF(!docShell)) {
     return nullptr;
   }
   docShell->SetOriginAttributes(aOriginAttributes);
   browser->SetDocShell(docShell);
 
   // get the system default window background colour
   LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
--- a/toolkit/components/browser/nsWebBrowser.h
+++ b/toolkit/components/browser/nsWebBrowser.h
@@ -103,17 +103,17 @@ class nsWebBrowser final : public nsIWeb
 
   void SetAllowDNSPrefetch(bool aAllowPrefetch);
   void FocusActivate();
   void FocusDeactivate();
 
   static already_AddRefed<nsWebBrowser> Create(
       nsIWebBrowserChrome* aContainerWindow, nsIWidget* aParentWidget,
       const mozilla::OriginAttributes& aOriginAttributes,
-      mozilla::dom::BrowsingContext* aBrowsingContext);
+      mozIDOMWindowProxy* aOpener, int aItemType);
 
  protected:
   virtual ~nsWebBrowser();
   NS_IMETHOD InternalDestroy();
 
   // XXXbz why are these NS_IMETHOD?  They're not interface methods!
   NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
   NS_IMETHOD EnsureDocShellTreeOwner();
--- a/xpfe/appshell/nsAppShellService.cpp
+++ b/xpfe/appshell/nsAppShellService.cpp
@@ -47,17 +47,16 @@
 
 #include "nsWebBrowser.h"
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
 #  include "EventTracer.h"
 #endif
 
 using namespace mozilla;
-using mozilla::dom::BrowsingContext;
 using mozilla::intl::LocaleService;
 
 // Default URL for the hidden window, can be overridden by a pref on Mac
 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
 
 class nsIAppShell;
 
 nsAppShellService::nsAppShellService()
@@ -456,27 +455,23 @@ nsAppShellService::CreateWindowlessBrows
     NS_ERROR("Couldn't create instance of stub widget");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv =
       widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Create a BrowsingContext for our windowless browser.
-  RefPtr<BrowsingContext> browsingContext =
-      BrowsingContext::Create(nullptr, nullptr, EmptyString(),
-                              aIsChrome ? BrowsingContext::Type::Chrome
-                                        : BrowsingContext::Type::Content);
-
   /* Next, we create an instance of nsWebBrowser. Instances of this class have
    * an associated doc shell, which is what we're interested in.
    */
   nsCOMPtr<nsIWebBrowser> browser =
-      nsWebBrowser::Create(stub, widget, OriginAttributes(), browsingContext);
+      nsWebBrowser::Create(stub, widget, OriginAttributes(), nullptr,
+                           aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
+                                     : nsIDocShellTreeItem::typeContentWrapper);
 
   if (NS_WARN_IF(!browser)) {
     NS_ERROR("Couldn't create instance of nsWebBrowser!");
     return NS_ERROR_FAILURE;
   }
 
   // Make sure the container window owns the the nsWebBrowser instance.
   stub->SetBrowser(browser);