author | Kershaw Chang <kechang@mozilla.com> |
Wed, 29 Oct 2014 19:11:00 +0100 | |
changeset 213163 | 01b25915ca374d803fa2e98f1dc47a9b59c007bf |
parent 213162 | fedce15e6ea22db45b0febcb8decce9ca200db80 |
child 213164 | f644da9988dc60571721050f5c9d9028064d0493 |
push id | 27742 |
push user | ryanvm@gmail.com |
push date | Thu, 30 Oct 2014 20:15:35 +0000 |
treeherder | mozilla-central@e0b505a37b1c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | khuey |
bugs | 1020172 |
milestone | 36.0a1 |
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
|
--- a/dom/ipc/ContentBridgeChild.cpp +++ b/dom/ipc/ContentBridgeChild.cpp @@ -76,23 +76,25 @@ PBlobChild* ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor, const BlobConstructorParams& params) { return PContentBridgeChild::SendPBlobConstructor(actor, params); } bool ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { return PContentBridgeChild::SendPBrowserConstructor(aActor, + aTabId, aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } // This implementation is identical to ContentChild::GetCPOWManager but we can't @@ -116,44 +118,48 @@ ContentBridgeChild::AllocPJavaScriptChil bool ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child) { return nsIContentChild::DeallocPJavaScriptChild(child); } PBrowserChild* -ContentBridgeChild::AllocPBrowserChild(const IPCTabContext &aContext, +ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext &aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { - return nsIContentChild::AllocPBrowserChild(aContext, + return nsIContentChild::AllocPBrowserChild(aTabId, + aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } bool ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild) { return nsIContentChild::DeallocPBrowserChild(aChild); } bool ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { return ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor, + aTabId, aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } PBlobChild*
--- a/dom/ipc/ContentBridgeChild.h +++ b/dom/ipc/ContentBridgeChild.h @@ -34,32 +34,35 @@ public: virtual PBlobChild* SendPBlobConstructor(PBlobChild* actor, const BlobConstructorParams& params); jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE; virtual bool SendPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; protected: virtual ~ContentBridgeChild(); - virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext, + virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual bool DeallocPBrowserChild(PBrowserChild*) MOZ_OVERRIDE; virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE; virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentBridgeParent.cpp +++ b/dom/ipc/ContentBridgeParent.cpp @@ -82,23 +82,25 @@ PBlobParent* ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor, const BlobConstructorParams& params) { return PContentBridgeParent::SendPBlobConstructor(actor, params); } PBrowserParent* ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { return PContentBridgeParent::SendPBrowserConstructor(aActor, + aTabId, aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } PBlobParent* @@ -121,23 +123,25 @@ ContentBridgeParent::AllocPJavaScriptPar bool ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent) { return nsIContentParent::DeallocPJavaScriptParent(parent); } PBrowserParent* -ContentBridgeParent::AllocPBrowserParent(const IPCTabContext &aContext, +ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext &aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { - return nsIContentParent::AllocPBrowserParent(aContext, + return nsIContentParent::AllocPBrowserParent(aTabId, + aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } bool ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
--- a/dom/ipc/ContentBridgeParent.h +++ b/dom/ipc/ContentBridgeParent.h @@ -29,16 +29,17 @@ public: Create(Transport* aTransport, ProcessId aOtherProcess); virtual PBlobParent* SendPBlobConstructor(PBlobParent* actor, const BlobConstructorParams& params) MOZ_OVERRIDE; virtual PBrowserParent* SendPBrowserConstructor(PBrowserParent* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE; @@ -82,17 +83,18 @@ protected: const InfallibleTArray<jsipc::CpowEntry>& aCpows, const IPC::Principal& aPrincipal) MOZ_OVERRIDE; virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() MOZ_OVERRIDE; virtual bool DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) MOZ_OVERRIDE; virtual PBrowserParent* - AllocPBrowserParent(const IPCTabContext &aContext, + AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext &aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual bool DeallocPBrowserParent(PBrowserParent*) MOZ_OVERRIDE; virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1113,47 +1113,52 @@ ContentChild::AllocPJavaScriptChild() bool ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild) { return nsIContentChild::DeallocPJavaScriptChild(aChild); } PBrowserChild* -ContentChild::AllocPBrowserChild(const IPCTabContext& aContext, +ContentChild::AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { - return nsIContentChild::AllocPBrowserChild(aContext, + return nsIContentChild::AllocPBrowserChild(aTabId, + aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } bool ContentChild::SendPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { return PContentChild::SendPBrowserConstructor(aActor, + aTabId, aContext, aChromeFlags, aCpID, aIsForApp, aIsForBrowser); } bool ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) { // This runs after AllocPBrowserChild() returns and the IPC machinery for this // PBrowserChild has been set up.
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -130,17 +130,18 @@ public: #endif virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE; PBackgroundChild* AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess) MOZ_OVERRIDE; - virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext, + virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser); virtual bool DeallocPBrowserChild(PBrowserChild*); virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&); virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*); @@ -372,23 +373,25 @@ public: virtual PFileDescriptorSetChild* AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE; virtual bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE; virtual bool SendPBrowserConstructor(PBrowserChild* actor, + const TabId& aTabId, const IPCTabContext& context, const uint32_t& chromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE; virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -128,16 +128,17 @@ #include "TabParent.h" #include "URIUtils.h" #include "nsIWebBrowserChrome.h" #include "nsIDocShell.h" #include "mozilla/net/NeckoMessageUtils.h" #include "gfxPrefs.h" #include "prio.h" #include "private/pprio.h" +#include "ContentProcessManager.h" #if defined(ANDROID) || defined(LINUX) #include "nsSystemInfo.h" #endif #if defined(XP_LINUX) #include "mozilla/Hal.h" #endif @@ -843,27 +844,24 @@ ContentParent::PreallocatedProcessReady( { #ifdef MOZ_NUWA_PROCESS return PreallocatedProcessManager::PreallocatedProcessReady(); #else return true; #endif } -typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap; -static GrandchildMap sGrandchildProcessMap; - -std::map<uint64_t, ContentParent*> sContentParentMap; - bool ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext, const hal::ProcessPriority& aPriority, - uint64_t* aId, + const TabId& aOpenerTabId, + ContentParentId* aCpId, bool* aIsForApp, - bool* aIsForBrowser) + bool* aIsForBrowser, + TabId* aTabId) { #if 0 if (!CanOpenBrowser(aContext)) { return false; } #endif nsRefPtr<ContentParent> cp; MaybeInvalidTabContext tc(aContext); @@ -882,50 +880,77 @@ ContentParent::RecvCreateChildProcess(co } else { cp = GetNewOrUsedBrowserProcess(/* isBrowserElement = */ true, aPriority, this); } if (!cp) { - *aId = 0; + *aCpId = 0; *aIsForApp = false; *aIsForBrowser = false; return true; } - *aId = cp->ChildID(); + *aCpId = cp->ChildID(); *aIsForApp = cp->IsForApp(); *aIsForBrowser = cp->IsForBrowser(); - sContentParentMap[*aId] = cp; - auto iter = sGrandchildProcessMap.find(this); - if (iter == sGrandchildProcessMap.end()) { - std::set<ContentParent*> children; - children.insert(cp); - sGrandchildProcessMap[this] = children; - } else { - iter->second.insert(cp); + + ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); + cpm->AddContentProcess(cp, this->ChildID()); + + if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) { + // Pre-allocate a TabId here to save one time IPC call at app startup. + *aTabId = AllocateTabId(aOpenerTabId, + aContext, + cp->ChildID()); + return (*aTabId != 0); } - return true; + + return false; } bool -ContentParent::AnswerBridgeToChildProcess(const uint64_t& id) +ContentParent::AnswerBridgeToChildProcess(const ContentParentId& aCpId) { - ContentParent* cp = sContentParentMap[id]; - auto iter = sGrandchildProcessMap.find(this); - if (iter != sGrandchildProcessMap.end() && - iter->second.find(cp) != iter->second.end()) { - return PContentBridge::Bridge(this, cp); - } else { - // You can't bridge to a process you didn't open! - KillHard(); - return false; + ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); + ContentParent* cp = cpm->GetContentProcessById(aCpId); + + if (cp) { + ContentParentId parentId; + if (cpm->GetParentProcessId(cp->ChildID(), &parentId) && + parentId == this->ChildID()) { + return PContentBridge::Bridge(this, cp); + } } + + // You can't bridge to a process you didn't open! + KillHard(); + return false; +} + +static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement) +{ + // Propagate the private-browsing status of the element's parent + // docshell to the remote docshell, via the chrome flags. + nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement); + MOZ_ASSERT(frameElement); + nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow(); + if (!win) { + NS_WARNING("Remote frame has no window"); + return nullptr; + } + nsIDocShell* docShell = win->GetDocShell(); + if (!docShell) { + NS_WARNING("Remote frame has no docshell"); + return nullptr; + } + + return docShell; } bool ContentParent::AnswerLoadPlugin(const uint32_t& aPluginId) { return mozilla::plugins::SetupBridge(aPluginId, this); } @@ -943,67 +968,69 @@ ContentParent::CreateBrowserOrApp(const ContentParent* aOpenerContentParent) { if (!sCanLaunchSubprocesses) { return nullptr; } ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement); bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default); + TabId tabId; + + nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement); + TabId openerTabId; + if (docShell) { + openerTabId = TabParent::GetTabIdFrom(docShell); + } if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) { nsRefPtr<TabParent> tp; nsRefPtr<nsIContentParent> constructorSender; if (isInContentProcess) { MOZ_ASSERT(aContext.IsBrowserElement()); - constructorSender = - CreateContentBridgeParent(aContext, initialPriority); + constructorSender = CreateContentBridgeParent(aContext, + initialPriority, + openerTabId, + &tabId); } else { - if (aOpenerContentParent) { - constructorSender = aOpenerContentParent; - } else { - constructorSender = - GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(), - initialPriority); - } + if (aOpenerContentParent) { + constructorSender = aOpenerContentParent; + } else { + constructorSender = + GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(), + initialPriority); + } + tabId = AllocateTabId(openerTabId, + aContext.AsIPCTabContext(), + constructorSender->ChildID()); } if (constructorSender) { uint32_t chromeFlags = 0; - // Propagate the private-browsing status of the element's parent - // docshell to the remote docshell, via the chrome flags. - nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement); - MOZ_ASSERT(frameElement); - nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow(); - if (!win) { - NS_WARNING("Remote frame has no window"); - return nullptr; - } - nsIDocShell* docShell = win->GetDocShell(); - if (!docShell) { - NS_WARNING("Remote frame has no docshell"); - return nullptr; - } nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell); if (loadContext && loadContext->UsePrivateBrowsing()) { chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; } bool affectLifetime; docShell->GetAffectPrivateSessionLifetime(&affectLifetime); if (affectLifetime) { chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME; } - nsRefPtr<TabParent> tp(new TabParent(constructorSender, + if (tabId == 0) { + return nullptr; + } + nsRefPtr<TabParent> tp(new TabParent(constructorSender, tabId, aContext, chromeFlags)); tp->SetOwnerElement(aFrameElement); PBrowserParent* browser = constructorSender->SendPBrowserConstructor( // DeallocPBrowserParent() releases this ref. tp.forget().take(), + tabId, aContext.AsIPCTabContext(), chromeFlags, constructorSender->ChildID(), constructorSender->IsForApp(), constructorSender->IsForBrowser()); return static_cast<TabParent*>(browser); } return nullptr; @@ -1013,17 +1040,20 @@ ContentParent::CreateBrowserOrApp(const // shouldn't be null, because we otherwise would have gone into the // !HasOwnApp() branch above. nsRefPtr<nsIContentParent> parent; bool reused = false; bool tookPreallocated = false; nsAutoString manifestURL; if (isInContentProcess) { - parent = CreateContentBridgeParent(aContext, initialPriority); + parent = CreateContentBridgeParent(aContext, + initialPriority, + openerTabId, + &tabId); } else { nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp(); if (!sAppContentParents) { sAppContentParents = new nsDataHashtable<nsStringHashKey, ContentParent*>(); } @@ -1083,30 +1113,34 @@ ContentParent::CreateBrowserOrApp(const if (!p) { p = GetNewOrPreallocatedAppProcess(ownApp, initialPriority, nullptr, &tookPreallocated); MOZ_ASSERT(p); sAppContentParents->Put(manifestURL, p); } + tabId = AllocateTabId(openerTabId, + aContext.AsIPCTabContext(), + p->ChildID()); parent = static_cast<nsIContentParent*>(p); } - if (!parent) { + if (!parent || (tabId == 0)) { return nullptr; } uint32_t chromeFlags = 0; - nsRefPtr<TabParent> tp = new TabParent(parent, aContext, chromeFlags); + nsRefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags); tp->SetOwnerElement(aFrameElement); PBrowserParent* browser = parent->SendPBrowserConstructor( // DeallocPBrowserParent() releases this ref. nsRefPtr<TabParent>(tp).forget().take(), + tabId, aContext.AsIPCTabContext(), chromeFlags, parent->ChildID(), parent->IsForApp(), parent->IsForBrowser()); if (isInContentProcess) { // Just return directly without the following check in content process. @@ -1139,37 +1173,43 @@ ContentParent::CreateBrowserOrApp(const parent->AsContentParent()->MaybeTakeCPUWakeLock(aFrameElement); return static_cast<TabParent*>(browser); } /*static*/ ContentBridgeParent* ContentParent::CreateContentBridgeParent(const TabContext& aContext, - const hal::ProcessPriority& aPriority) + const hal::ProcessPriority& aPriority, + const TabId& aOpenerTabId, + /*out*/ TabId* aTabId) { + MOZ_ASSERT(aTabId); + ContentChild* child = ContentChild::GetSingleton(); - uint64_t id; + ContentParentId cpId; bool isForApp; bool isForBrowser; if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(), aPriority, - &id, + aOpenerTabId, + &cpId, &isForApp, - &isForBrowser)) { + &isForBrowser, + aTabId)) { return nullptr; } - if (id == 0) { + if (cpId == 0) { return nullptr; } - if (!child->CallBridgeToChildProcess(id)) { + if (!child->CallBridgeToChildProcess(cpId)) { return nullptr; } ContentBridgeParent* parent = child->GetLastBridge(); - parent->SetChildID(id); + parent->SetChildID(cpId); parent->SetIsForApp(isForApp); parent->SetIsForBrowser(isForBrowser); return parent; } void ContentParent::GetAll(nsTArray<ContentParent*>& aArray) { @@ -1495,23 +1535,16 @@ ContentParent::MarkAsDead() sPrivateContent->RemoveElement(this); if (!sPrivateContent->Length()) { delete sPrivateContent; sPrivateContent = nullptr; } } mIsAlive = false; - - sGrandchildProcessMap.erase(this); - for (auto iter = sGrandchildProcessMap.begin(); - iter != sGrandchildProcessMap.end(); - iter++) { - iter->second.erase(this); - } } void ContentParent::OnChannelError() { nsRefPtr<ContentParent> content(this); #ifdef MOZ_NUWA_PROCESS // Handle app or Nuwa process exit before normal channel error handling. @@ -1739,27 +1772,27 @@ ContentParent::ActorDestroy(ActorDestroy // |this|. If so, when we go out of scope here, we're deleted and // all hell breaks loose. // // This runnable ensures that a reference to |this| lives on at // least until after the current task finishes running. NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this)); // Destroy any processes created by this ContentParent - auto iter = sGrandchildProcessMap.find(this); - if (iter != sGrandchildProcessMap.end()) { - for(auto child = iter->second.begin(); - child != iter->second.end(); - child++) { - MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(*child, &ContentParent::ShutDownProcess, - /* closeWithError */ false)); - } + ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); + nsTArray<ContentParentId> childIDArray = + cpm->GetAllChildProcessById(this->ChildID()); + for(uint32_t i = 0; i < childIDArray.Length(); i++) { + ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]); + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(cp, &ContentParent::ShutDownProcess, + /* closeWithError */ false)); } + cpm->RemoveContentProcess(this->ChildID()); } void ContentParent::NotifyTabDestroying(PBrowserParent* aTab) { // There can be more than one PBrowser for a given app process // because of popup windows. PBrowsers can also destroy // concurrently. When all the PBrowsers are destroying, kick off @@ -1912,16 +1945,18 @@ ContentParent::ContentParent(mozIApplica } mSubprocess->LaunchAndWaitForProcessHandle(extraArgs); Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle()); InitInternal(aInitialPriority, true, /* Setup off-main thread compositing */ true /* Send registered chrome */); + + ContentProcessManager::GetSingleton()->AddContentProcess(this); } #ifdef MOZ_NUWA_PROCESS static const mozilla::ipc::FileDescriptor* FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds, ProtocolId aProtoId) { for (unsigned int i = 0; i < aFds.Length(); i++) { @@ -1989,16 +2024,18 @@ ContentParent::ContentParent(ContentPare priority = PROCESS_PRIORITY_PREALLOC; } else { priority = PROCESS_PRIORITY_FOREGROUND; } InitInternal(priority, false, /* Setup Off-main thread compositing */ false /* Send registered chrome */); + + ContentProcessManager::GetSingleton()->AddContentProcess(this); } #endif // MOZ_NUWA_PROCESS ContentParent::~ContentParent() { if (mForceKillTask) { mForceKillTask->Cancel(); } @@ -2850,23 +2887,25 @@ ContentParent::AllocPJavaScriptParent() bool ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent) { return nsIContentParent::DeallocPJavaScriptParent(parent); } PBrowserParent* -ContentParent::AllocPBrowserParent(const IPCTabContext& aContext, +ContentParent::AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) { - return nsIContentParent::AllocPBrowserParent(aContext, + return nsIContentParent::AllocPBrowserParent(aTabId, + aContext, aChromeFlags, aCpId, aIsForApp, aIsForBrowser); } bool ContentParent::DeallocPBrowserParent(PBrowserParent* frame) @@ -3859,23 +3898,25 @@ bool ContentParent::RecvSystemMessageHandled() { SystemMessageHandledListener::OnSystemMessageHandled(); return true; } PBrowserParent* ContentParent::SendPBrowserConstructor(PBrowserParent* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) { return PContentParent::SendPBrowserConstructor(aActor, + aTabId, aContext, aChromeFlags, aCpId, aIsForApp, aIsForBrowser); } bool @@ -4167,16 +4208,76 @@ ContentParent::NotifyUpdatedDictionaries InfallibleTArray<nsString> dictionaries; spellChecker->GetDictionaryList(&dictionaries); for (size_t i = 0; i < processes.Length(); ++i) { unused << processes[i]->SendUpdateDictionaryList(dictionaries); } } +/*static*/ TabId +ContentParent::AllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aCpId) +{ + TabId tabId; + if (XRE_GetProcessType() == GeckoProcessType_Default) { + ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); + tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId); + } + else { + ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId, + aContext, + aCpId, + &tabId); + } + return tabId; +} + +/*static*/ void +ContentParent::DeallocateTabId(const TabId& aTabId, + const ContentParentId& aCpId) +{ + if (XRE_GetProcessType() == GeckoProcessType_Default) { + ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId, + aTabId); + } + else { + ContentChild::GetSingleton()->SendDeallocateTabId(aTabId); + } +} + +bool +ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aCpId, + TabId* aTabId) +{ + *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId); + if (!(*aTabId)) { + return false; + } + return true; +} + +bool +ContentParent::RecvDeallocateTabId(const TabId& aTabId) +{ + DeallocateTabId(aTabId, this->ChildID()); + return true; +} + +nsTArray<TabContext> +ContentParent::GetManagedTabContext() +{ + return Move(ContentProcessManager::GetSingleton()-> + GetTabContextByContentProcess(this->ChildID())); +} + + } // namespace dom } // namespace mozilla NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver) NS_IMETHODIMP ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) { mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -138,20 +138,22 @@ public: static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray); static bool IgnoreIPCPrincipal(); static void NotifyUpdatedDictionaries(); virtual bool RecvCreateChildProcess(const IPCTabContext& aContext, const hal::ProcessPriority& aPriority, - uint64_t* aId, + const TabId& aOpenerTabId, + ContentParentId* aCpId, bool* aIsForApp, - bool* aIsForBrowser) MOZ_OVERRIDE; - virtual bool AnswerBridgeToChildProcess(const uint64_t& id) MOZ_OVERRIDE; + bool* aIsForBrowser, + TabId* aTabId) MOZ_OVERRIDE; + virtual bool AnswerBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE; virtual bool AnswerLoadPlugin(const uint32_t& aPluginId) MOZ_OVERRIDE; virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch, nsTArray<PluginTag>* aPlugins, uint32_t* aNewPluginEpoch) MOZ_OVERRIDE; NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver) @@ -179,16 +181,23 @@ public: void NotifyTabDestroyed(PBrowserParent* aTab, bool aNotifiedDestroying); TestShellParent* CreateTestShell(); bool DestroyTestShell(TestShellParent* aTestShell); TestShellParent* GetTestShellSingleton(); jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE; + static TabId + AllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aCpId); + static void + DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId); + void ReportChildAlreadyBlocked(); bool RequestRunToCompletion(); bool IsAlive(); virtual bool IsForApp() MOZ_OVERRIDE; virtual bool IsForBrowser() MOZ_OVERRIDE { return mIsForBrowser; @@ -286,16 +295,24 @@ public: bool CycleCollectWithLogs(bool aDumpAllTraces, nsICycleCollectorLogSink* aSink, nsIDumpGCAndCCLogsCallback* aCallback); virtual PBlobParent* SendPBlobConstructor( PBlobParent* aActor, const BlobConstructorParams& aParams) MOZ_OVERRIDE; + virtual bool RecvAllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aCpId, + TabId* aTabId) MOZ_OVERRIDE; + + virtual bool RecvDeallocateTabId(const TabId& aTabId) MOZ_OVERRIDE; + + nsTArray<TabContext> GetManagedTabContext(); protected: void OnChannelConnected(int32_t pid) MOZ_OVERRIDE; virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE; void OnNuwaForkTimeout(); bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE; private: @@ -314,22 +331,25 @@ private: GetNewOrPreallocatedAppProcess(mozIApplication* aApp, hal::ProcessPriority aInitialPriority, ContentParent* aOpener, /*out*/ bool* aTookPreAllocated = nullptr); static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement); static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext, - const hal::ProcessPriority& aPriority); + const hal::ProcessPriority& aPriority, + const TabId& aOpenerTabId, + /*out*/ TabId* aTabId); // Hide the raw constructor methods since we don't want client code // using them. virtual PBrowserParent* SendPBrowserConstructor( PBrowserParent* actor, + const TabId& aTabId, const IPCTabContext& context, const uint32_t& chromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; using PContentParent::SendPTestShellConstructor; // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be @@ -424,17 +444,18 @@ private: virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline, InfallibleTArray<nsString>* dictionaries, ClipboardCapabilities* clipboardCaps) MOZ_OVERRIDE; virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE; virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE; - virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext, + virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) MOZ_OVERRIDE; virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE; virtual PDeviceStorageRequestParent* AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
new file mode 100644 --- /dev/null +++ b/dom/ipc/ContentProcessManager.cpp @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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 "ContentProcessManager.h" +#include "ContentParent.h" + +#include "mozilla/StaticPtr.h" +#include "mozilla/ClearOnShutdown.h" + +#include "nsPrintfCString.h" + +// XXX need another bug to move this to a common header. +#ifdef DISABLE_ASSERTS_FOR_FUZZING +#define ASSERT_UNLESS_FUZZING(...) do { } while (0) +#else +#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__) +#endif + +namespace mozilla { +namespace dom { + +static uint64_t gTabId = 0; + +/* static */ +StaticAutoPtr<ContentProcessManager> +ContentProcessManager::sSingleton; + +/* static */ ContentProcessManager* +ContentProcessManager::GetSingleton() +{ + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + if (!sSingleton) { + sSingleton = new ContentProcessManager(); + ClearOnShutdown(&sSingleton); + } + return sSingleton; +} + +void +ContentProcessManager::AddContentProcess(ContentParent* aChildCp, + const ContentParentId& aParentCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aChildCp); + + ContentProcessInfo info; + info.mCp = aChildCp; + info.mParentCpId = aParentCpId; + mContentParentMap[aChildCp->ChildID()] = info; +} + +void +ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end()); + + mContentParentMap.erase(aChildCpId); + for (auto iter = mContentParentMap.begin(); + iter != mContentParentMap.end(); + ++iter) { + if (!iter->second.mChildrenCpId.empty()) { + iter->second.mChildrenCpId.erase(aChildCpId); + } + } +} + +bool +ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId, + const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + auto iter = mContentParentMap.find(aParentCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING("Parent process should be already in map!"); + return false; + } + iter->second.mChildrenCpId.insert(aChildCpId); + return true; +} + +bool +ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId, + /*out*/ ContentParentId* aParentCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return false; + } + *aParentCpId = iter->second.mParentCpId; + return true; +} + +ContentParent* +ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return nullptr; + } + return iter->second.mCp; +} + +nsTArray<ContentParentId> +ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsTArray<ContentParentId> cpIdArray; + auto iter = mContentParentMap.find(aParentCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return Move(cpIdArray); + } + + for (auto cpIter = iter->second.mChildrenCpId.begin(); + cpIter != iter->second.mChildrenCpId.end(); + ++cpIter) { + cpIdArray.AppendElement(*cpIter); + } + + return Move(cpIdArray); +} + +TabId +ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return TabId(0); + } + + struct RemoteFrameInfo info; + + const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext(); + // If it's a PopupIPCTabContext, it's the case that a TabChild want to + // open a new tab. aOpenerTabId has to be it's parent frame's opener id. + if (appBrowser.type() == IPCTabAppBrowserContext::TPopupIPCTabContext) { + auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId); + if (remoteFrameIter == iter->second.mRemoteFrames.end()) { + ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id."); + return TabId(0); + } + + info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId; + + const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext(); + MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId); + + remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId()); + if (remoteFrameIter == iter->second.mRemoteFrames.end()) { + ASSERT_UNLESS_FUZZING("Failed to find tab id."); + return TabId(0); + } + + info.mContext = remoteFrameIter->second.mContext; + } + else { + MaybeInvalidTabContext tc(aContext); + if (!tc.IsValid()) { + NS_ERROR(nsPrintfCString("Received an invalid TabContext from " + "the child process. (%s)", + tc.GetInvalidReason()).get()); + return TabId(0); + } + info.mOpenerTabId = aOpenerTabId; + info.mContext = tc.GetTabContext(); + } + + mUniqueId = ++gTabId; + iter->second.mRemoteFrames[mUniqueId] = info; + + return mUniqueId; +} + +void +ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId, + const TabId& aChildTabId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return; + } + + auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId); + if (remoteFrameIter != iter->second.mRemoteFrames.end()) { + iter->second.mRemoteFrames.erase(aChildTabId); + } +} + +nsTArray<uint64_t> +ContentProcessManager::GetAppIdsByContentProcess(const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsTArray<uint64_t> appIdArray; + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return Move(appIdArray); + } + + for (auto remoteFrameIter = iter->second.mRemoteFrames.begin(); + remoteFrameIter != iter->second.mRemoteFrames.end(); + ++remoteFrameIter) { + appIdArray.AppendElement(remoteFrameIter->second.mContext.OwnOrContainingAppId()); + } + + return Move(appIdArray); +} + +nsTArray<TabContext> +ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsTArray<TabContext> tabContextArray; + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return Move(tabContextArray); + } + + for (auto remoteFrameIter = iter->second.mRemoteFrames.begin(); + remoteFrameIter != iter->second.mRemoteFrames.end(); + ++remoteFrameIter) { + tabContextArray.AppendElement(remoteFrameIter->second.mContext); + } + + return Move(tabContextArray); +} + +bool +ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId, + const TabId& aChildTabId, + /*out*/TabId* aOpenerTabId) +{ + MOZ_ASSERT(NS_IsMainThread()); + auto iter = mContentParentMap.find(aChildCpId); + if (NS_WARN_IF(iter == mContentParentMap.end())) { + ASSERT_UNLESS_FUZZING(); + return false; + } + + auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId); + if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) { + ASSERT_UNLESS_FUZZING(); + return false; + } + + *aOpenerTabId = remoteFrameIter->second.mOpenerTabId; + + return true; +} + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/ipc/ContentProcessManager.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_ContentProcessManager_h +#define mozilla_dom_ContentProcessManager_h + +#include <map> +#include <set> +#include "mozilla/StaticPtr.h" +#include "mozilla/dom/TabContext.h" +#include "mozilla/dom/ipc/IdType.h" +#include "nsTArray.h" + +namespace mozilla { +namespace dom { +class ContentParent; + +struct RemoteFrameInfo +{ + TabId mOpenerTabId; + TabContext mContext; +}; + +struct ContentProcessInfo +{ + ContentParent* mCp; + ContentParentId mParentCpId; + std::set<ContentParentId> mChildrenCpId; + std::map<TabId, RemoteFrameInfo> mRemoteFrames; +}; + +class ContentProcessManager MOZ_FINAL +{ +public: + static ContentProcessManager* GetSingleton(); + ~ContentProcessManager() {MOZ_COUNT_DTOR(ContentProcessManager);}; + + /** + * Add a new content process into the map. + * If aParentCpId is not 0, it's a nested content process. + */ + void AddContentProcess(ContentParent* aChildCp, + const ContentParentId& aParentCpId = ContentParentId(0)); + /** + * Remove the content process by id. + */ + void RemoveContentProcess(const ContentParentId& aChildCpId); + /** + * Add a grandchild content process into the map. + * aParentCpId must be already added in the map by AddContentProcess(). + */ + bool AddGrandchildProcess(const ContentParentId& aParentCpId, + const ContentParentId& aChildCpId); + /** + * Get the parent process's id by child process's id. + * Used to check if a child really belongs to the parent. + */ + bool GetParentProcessId(const ContentParentId& aChildCpId, + /*out*/ ContentParentId* aParentCpId); + /** + * Return the ContentParent pointer by id. + */ + ContentParent* GetContentProcessById(const ContentParentId& aChildCpId); + + /** + * Return a list of all child process's id. + */ + nsTArray<ContentParentId> + GetAllChildProcessById(const ContentParentId& aParentCpId); + + /** + * Allocate a tab id for the given content process's id. + * Used when a content process wants to create a new tab. aOpenerTabId and + * aContext are saved in RemoteFrameInfo, which is a part of ContentProcessInfo. + * We can use the tab id and process id to locate the TabContext for future use. + */ + TabId AllocateTabId(const TabId& aOpenerTabId, + const IPCTabContext& aContext, + const ContentParentId& aChildCpId); + + /** + * Remove the RemoteFrameInfo by the given process and tab id. + */ + void DeallocateTabId(const ContentParentId& aChildCpId, + const TabId& aChildTabId); + + /** + * Get all app ids which are inside the given content process. + * XXX Currently not used. Plan to be used for bug 1020186. + */ + nsTArray<uint64_t> + GetAppIdsByContentProcess(const ContentParentId& aChildCpId); + + /** + * Get all TabContext which are inside the given content process. + * Used for AppProcessChecker to cehck app status. + */ + nsTArray<TabContext> + GetTabContextByContentProcess(const ContentParentId& aChildCpId); + + /** + * Query a tab's opener id by the given process and tab id. + * XXX Currently not used. Plan to be used for bug 1020179. + */ + bool GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId, + const TabId& aChildTabId, + /*out*/ TabId* aOpenerTabId); + +private: + static StaticAutoPtr<ContentProcessManager> sSingleton; + TabId mUniqueId; + std::map<ContentParentId, ContentProcessInfo> mContentParentMap; + + ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);}; +}; + +} // namespace dom +} // namespace mozilla +#endif \ No newline at end of file
--- a/dom/ipc/IdType.h +++ b/dom/ipc/IdType.h @@ -2,19 +2,26 @@ /* vim: set sw=4 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_IdType_h #define mozilla_dom_IdType_h +#include "ipc/IPCMessageUtils.h" + +namespace IPC { +template<typename T> struct ParamTraits; +} + namespace mozilla { namespace dom { class ContentParent; +class TabParent; template<typename T> class IdType { friend struct IPC::ParamTraits<IdType<T>>; @@ -33,16 +40,17 @@ public: bool operator<(const IdType& rhs) { return mId < rhs.mId; } private: uint64_t mId; }; +typedef IdType<TabParent> TabId; typedef IdType<ContentParent> ContentParentId; } // namespace dom } // namespace mozilla namespace IPC { template<typename T>
new file mode 100644 --- /dev/null +++ b/dom/ipc/PBrowserOrId.ipdlh @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=c: */ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PBrowser; + +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; + +namespace mozilla { +namespace dom { + +union PBrowserOrId +{ + nullable PBrowser; + TabId; +}; + +} // namespace dom +} // namespace mozilla \ No newline at end of file
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -65,16 +65,17 @@ using struct mozilla::void_t from "ipc/I using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h"; using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h"; using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h"; using mozilla::dom::AudioChannelState from "AudioChannelCommon.h"; using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h"; using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h"; using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h"; using gfxIntSize from "nsSize.h"; +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h"; union ChromeRegistryItem { ChromePackage; OverrideMapping; ResourceMapping; }; @@ -387,17 +388,17 @@ both: // browser element. // // This allows the parent to prevent a malicious child from escalating its // privileges by requesting a PBrowser corresponding to a highly-privileged // app; the child can only request privileges for an app which the child has // access to (in the form of a TabChild). // // Keep the last 3 attributes in sync with GetProcessAttributes! - async PBrowser(IPCTabContext context, uint32_t chromeFlags, + async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags, ContentParentId cpId, bool isForApp, bool isForBrowser); async PBlob(BlobConstructorParams params); PFileDescriptorSet(FileDescriptor fd); child: /** @@ -528,19 +529,20 @@ parent: */ sync GetProcessAttributes() returns (ContentParentId cpId, bool isForApp, bool isForBrowser); sync GetXPCOMProcessAttributes() returns (bool isOffline, nsString[] dictionaries, ClipboardCapabilities clipboardCaps); sync CreateChildProcess(IPCTabContext context, - ProcessPriority priority) - returns (uint64_t id, bool isForApp, bool isForBrowser); - intr BridgeToChildProcess(uint64_t id); + ProcessPriority priority, + TabId openerTabId) + returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId); + intr BridgeToChildProcess(ContentParentId cpId); /** * This call connects the content process to a plugin process. While this * call runs, a new PluginModuleParent will be created in the ContentChild * via bridging. The corresponding PluginModuleChild will live in the plugin * process. We use intr semantics here to ensure that the PluginModuleParent * allocation message is dispatched before LoadPlugin returns. */ @@ -770,15 +772,23 @@ parent: // Use only for testing! sync GetFileReferences(PersistenceType persistenceType, nsCString origin, nsString databaseName, int64_t fileId) returns (int32_t refCnt, int32_t dBRefCnt, int32_t sliceRefCnt, bool result); + /** + * Tell the chrome process there is an creation of PBrowser. + * return a system-wise unique Id. + */ + sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId) + returns (TabId tabId); + async DeallocateTabId(TabId tabId); + both: AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal); }; } }
--- a/dom/ipc/PContentBridge.ipdl +++ b/dom/ipc/PContentBridge.ipdl @@ -9,16 +9,17 @@ include protocol PBrowser; include protocol PContent; include protocol PJavaScript; include DOMTypes; include JavaScriptTypes; include PTabContext; using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h"; +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h"; namespace mozilla { namespace dom { /* * PContentBridge allows us to represent a parent/child relationship between two * child processes. When a child process wants to open its own child, it asks @@ -37,17 +38,17 @@ prio(normal upto high) intr protocol PCo parent: sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal) returns (nsString[] retval); both: // Both the parent and the child can construct the PBrowser. // See the comment in PContent::PBrowser(). - async PBrowser(IPCTabContext context, uint32_t chromeFlags, + async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags, ContentParentId cpId, bool isForApp, bool isForBrowser); async PBlob(BlobConstructorParams params); async PJavaScript(); AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal);
--- a/dom/ipc/PTabContext.ipdlh +++ b/dom/ipc/PTabContext.ipdlh @@ -1,16 +1,16 @@ /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */ /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PBrowser; - +include PBrowserOrId; using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h"; namespace mozilla { namespace dom { // An IPCTabContext which corresponds to a PBrowser opened by a child when it // receives window.open(). @@ -22,17 +22,17 @@ namespace dom { // If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal // to the opener's app-id. // // It's an error to set isBrowserElement == false if opener is a browser // element. Such a PopupIPCTabContext should be rejected by code which receives // it. struct PopupIPCTabContext { - PBrowser opener; + PBrowserOrId opener; bool isBrowserElement; }; // An IPCTabContext which corresponds to an app frame. struct AppFrameIPCTabContext { // The ID of the app this frame corresponds to. May be NO_APP_ID. uint32_t ownAppId;
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -728,33 +728,34 @@ private: mInfo->FireCallback(); return NS_OK; } }; StaticRefPtr<TabChild> sPreallocatedTab; /*static*/ -std::map<uint64_t, nsRefPtr<TabChild> >& +std::map<TabId, nsRefPtr<TabChild>>& TabChild::NestedTabChildMap() { MOZ_ASSERT(NS_IsMainThread()); - static std::map<uint64_t, nsRefPtr<TabChild> > sNestedTabChildMap; + static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap; return sNestedTabChildMap; } /*static*/ void TabChild::PreloadSlowThings() { MOZ_ASSERT(!sPreallocatedTab); // Pass nullptr to aManager since at this point the TabChild is // not connected to any manager. Any attempt to use the TabChild // in IPC will crash. nsRefPtr<TabChild> tab(new TabChild(nullptr, + TabId(0), TabContext(), /* chromeFlags */ 0)); if (!NS_SUCCEEDED(tab->Init()) || !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) { return; } // Just load and compile these scripts, but don't run them. tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true); // Load, compile, and run these scripts. @@ -775,41 +776,44 @@ TabChild::PreloadSlowThings() } sPreallocatedTab = tab; ClearOnShutdown(&sPreallocatedTab); } /*static*/ already_AddRefed<TabChild> TabChild::Create(nsIContentChild* aManager, + const TabId& aTabId, const TabContext &aContext, uint32_t aChromeFlags) { if (sPreallocatedTab && sPreallocatedTab->mChromeFlags == aChromeFlags && aContext.IsBrowserOrApp()) { nsRefPtr<TabChild> child = sPreallocatedTab.get(); sPreallocatedTab = nullptr; MOZ_ASSERT(!child->mTriedBrowserInit); child->mManager = aManager; + child->SetTabId(aTabId); child->SetTabContext(aContext); child->NotifyTabContextUpdated(); return child.forget(); } - nsRefPtr<TabChild> iframe = new TabChild(aManager, + nsRefPtr<TabChild> iframe = new TabChild(aManager, aTabId, aContext, aChromeFlags); return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr; } TabChild::TabChild(nsIContentChild* aManager, + const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags) : TabContext(aContext) , mRemoteFrame(nullptr) , mManager(aManager) , mChromeFlags(aChromeFlags) , mLayersId(0) , mOuterRect(0, 0, 0, 0) @@ -823,25 +827,31 @@ TabChild::TabChild(nsIContentChild* aMan , mUpdateHitRegion(false) , mPendingTouchPreventedResponse(false) , mPendingTouchPreventedBlockId(0) , mTouchEndCancelled(false) , mEndTouchIsClick(false) , mIgnoreKeyPressEvent(false) , mActiveElementManager(new ActiveElementManager()) , mHasValidInnerSize(false) - , mUniqueId(0) , mDestroyed(false) + , mUniqueId(aTabId) { if (!sActiveDurationMsSet) { Preferences::AddIntVarCache(&sActiveDurationMs, "ui.touch_activation.duration_ms", sActiveDurationMs); sActiveDurationMsSet = true; } + + // preloaded TabChild should not be added to child map + if (mUniqueId) { + MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end()); + NestedTabChildMap()[mUniqueId] = this; + } } NS_IMETHODIMP TabChild::HandleEvent(nsIDOMEvent* aEvent) { nsAutoString eventType; aEvent->GetType(eventType); if (eventType.EqualsLiteral("DOMMetaAdded")) { @@ -1429,36 +1439,46 @@ TabChild::BrowserFrameProvideWindow(nsID nsIURI* aURI, const nsAString& aName, const nsACString& aFeatures, bool* aWindowIsNew, nsIDOMWindow** aReturn) { *aReturn = nullptr; - nsRefPtr<TabChild> newChild = - new TabChild(ContentChild::GetSingleton(), - /* TabContext */ *this, /* chromeFlags */ 0); - if (!NS_SUCCEEDED(newChild->Init())) { - return NS_ERROR_ABORT; - } + ContentChild* cc = ContentChild::GetSingleton(); + const TabId openerTabId = GetTabId(); // We must use PopupIPCTabContext here; ContentParent will not accept the // result of this->AsIPCTabContext() (which will be a // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security // reasons. PopupIPCTabContext context; - context.openerChild() = this; + context.opener() = openerTabId; context.isBrowserElement() = IsBrowserElement(); - ContentChild* cc = static_cast<ContentChild*>(Manager()); + IPCTabContext ipcContext(context, mScrolling); + + TabId tabId; + cc->SendAllocateTabId(openerTabId, + ipcContext, + cc->GetID(), + &tabId); + + nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId, + /* TabContext */ *this, /* chromeFlags */ 0); + if (NS_FAILED(newChild->Init())) { + return NS_ERROR_ABORT; + } + + context.opener() = this; unused << Manager()->SendPBrowserConstructor( // We release this ref in DeallocPBrowserChild nsRefPtr<TabChild>(newChild).forget().take(), - IPCTabContext(context, mScrolling), /* chromeFlags */ 0, + tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0, cc->GetID(), cc->IsForApp(), cc->IsForBrowser()); nsAutoCString spec; if (aURI) { aURI->GetSpec(spec); } NS_ConvertUTF8toUTF16 url(spec); @@ -1558,18 +1578,18 @@ TabChild::ActorDestroy(ActorDestroyReaso static_cast<nsFrameMessageManager*> (mTabChildGlobal->mMessageManager.get())->Disconnect(); mTabChildGlobal->mMessageManager = nullptr; } CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get()); compositorChild->CancelNotifyAfterRemotePaint(this); - if (Id() != 0) { - NestedTabChildMap().erase(Id()); + if (GetTabId() != 0) { + NestedTabChildMap().erase(GetTabId()); } } TabChild::~TabChild() { DestroyWindow(); nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
--- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -29,16 +29,17 @@ #include "nsITooltipListener.h" #include "mozilla/Attributes.h" #include "mozilla/dom/TabContext.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventForwards.h" #include "mozilla/layers/CompositorTypes.h" #include "nsIWebBrowserChrome3.h" +#include "mozilla/dom/ipc/IdType.h" class nsICachedFileDescriptorListener; class nsIDOMWindowUtils; namespace mozilla { namespace layout { class RenderFrameChild; } @@ -249,48 +250,35 @@ class TabChild MOZ_FINAL : public TabChi public nsITooltipListener { typedef mozilla::dom::ClonedMessageData ClonedMessageData; typedef mozilla::layout::RenderFrameChild RenderFrameChild; typedef mozilla::layout::ScrollingBehavior ScrollingBehavior; typedef mozilla::layers::ActiveElementManager ActiveElementManager; public: - static std::map<uint64_t, nsRefPtr<TabChild> >& NestedTabChildMap(); + static std::map<TabId, nsRefPtr<TabChild>>& NestedTabChildMap(); public: /** * This is expected to be called off the critical path to content * startup. This is an opportunity to load things that are slow * on the critical path. */ static void PreloadSlowThings(); /** Return a TabChild with the given attributes. */ static already_AddRefed<TabChild> - Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags); + Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags); bool IsRootContentDocument(); - const uint64_t Id() const { - return mUniqueId; - } - - static uint64_t - GetTabChildId(TabChild* aTabChild) - { - MOZ_ASSERT(NS_IsMainThread()); - if (aTabChild->Id() != 0) { - return aTabChild->Id(); - } - static uint64_t sId = 0; - sId++; - aTabChild->mUniqueId = sId; - NestedTabChildMap()[sId] = aTabChild; - return sId; + const TabId GetTabId() const { + MOZ_ASSERT(mUniqueId != 0); + return mUniqueId; } NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIWEBBROWSERCHROME NS_DECL_NSIWEBBROWSERCHROME2 NS_DECL_NSIEMBEDDINGSITEWINDOW NS_DECL_NSIWEBBROWSERCHROMEFOCUS NS_DECL_NSIINTERFACEREQUESTOR @@ -514,17 +502,20 @@ private: /** * Create a new TabChild object. * * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app * frame in the hierarchy which contains us. * * |aIsBrowserElement| indicates whether we're a browser (but not an app). */ - TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags); + TabChild(nsIContentChild* aManager, + const TabId& aTabId, + const TabContext& aContext, + uint32_t aChromeFlags); nsresult Init(); class DelayedFireSingleTapEvent; class DelayedFireContextMenuEvent; // Notify others that our TabContext has been updated. (At the moment, this // sets the appropriate app-id and is-browser flags on our docshell.) @@ -562,16 +553,24 @@ private: bool* aWindowIsNew, nsIDOMWindow** aReturn); bool HasValidInnerSize(); void SendPendingTouchPreventedResponse(bool aPreventDefault, const ScrollableLayerGuid& aGuid); + void SetTabId(const TabId& aTabId) + { + MOZ_ASSERT(mUniqueId == 0); + + mUniqueId = aTabId; + NestedTabChildMap()[mUniqueId] = this; + } + class CachedFileDescriptorInfo; class CachedFileDescriptorCallbackRunnable; TextureFactoryIdentifier mTextureFactoryIdentifier; nsCOMPtr<nsIWebNavigation> mWebNav; nsCOMPtr<nsIWidget> mWidget; nsCOMPtr<nsIURI> mLastURI; RenderFrameChild* mRemoteFrame; @@ -605,18 +604,18 @@ private: void FireSingleTapEvent(LayoutDevicePoint aPoint); bool mTouchEndCancelled; bool mEndTouchIsClick; bool mIgnoreKeyPressEvent; nsRefPtr<ActiveElementManager> mActiveElementManager; bool mHasValidInnerSize; - uint64_t mUniqueId; bool mDestroyed; + TabId mUniqueId; DISALLOW_EVIL_CONSTRUCTORS(TabChild); }; } } #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabContext.cpp +++ b/dom/ipc/TabContext.cpp @@ -251,29 +251,34 @@ MaybeInvalidTabContext::MaybeInvalidTabC uint32_t containingAppId = NO_APP_ID; const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext(); switch(appBrowser.type()) { case IPCTabAppBrowserContext::TPopupIPCTabContext: { const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext(); TabContext *context; - if (ipcContext.openerParent()) { - context = static_cast<TabParent*>(ipcContext.openerParent()); + if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) { + context = static_cast<TabParent*>(ipcContext.opener().get_PBrowserParent()); if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) { // If the TabParent corresponds to a browser element, then it can only // open other browser elements, for security reasons. We should have // checked this before calling the TabContext constructor, so this is // a fatal error. mInvalidReason = "Child is-browser process tried to " "open a non-browser tab."; return; } - } else if (ipcContext.openerChild()) { - context = static_cast<TabChild*>(ipcContext.openerChild()); + } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) { + context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild()); + } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) { + // We should never get here because this PopupIPCTabContext is only + // used for allocating a new tab id, not for allocating a PBrowser. + mInvalidReason = "Child process tried to open an tab without the opener information."; + return; } else { // This should be unreachable because PopupIPCTabContext::opener is not a // nullable field. mInvalidReason = "PopupIPCTabContext::opener was null (?!)."; return; } // Browser elements can't nest other browser elements. So if
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -213,17 +213,20 @@ TabParent* sEventCapturer; TabParent *TabParent::mIMETabParent = nullptr; NS_IMPL_ISUPPORTS(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI, nsISupportsWeakReference) -TabParent::TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags) +TabParent::TabParent(nsIContentParent* aManager, + const TabId& aTabId, + const TabContext& aContext, + uint32_t aChromeFlags) : TabContext(aContext) , mFrameElement(nullptr) , mIMESelectionAnchor(0) , mIMESelectionFocus(0) , mIMEComposing(false) , mIMECompositionEnding(false) , mIMECompositionStart(0) , mIMESeqno(0) @@ -237,16 +240,17 @@ TabParent::TabParent(nsIContentParent* a , mShown(false) , mUpdatedDimensions(false) , mManager(aManager) , mMarkedDestroying(false) , mIsDestroyed(false) , mAppPackageFileDescriptorSent(false) , mSendOfflineStatus(true) , mChromeFlags(aChromeFlags) + , mTabId(aTabId) { MOZ_ASSERT(aManager); } TabParent::~TabParent() { } @@ -313,17 +317,23 @@ TabParent::Destroy() mMarkedDestroying = true; } bool TabParent::Recv__delete__() { if (XRE_GetProcessType() == GeckoProcessType_Default) { Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying); + ContentParent::DeallocateTabId(mTabId, + Manager()->AsContentParent()->ChildID()); } + else { + ContentParent::DeallocateTabId(mTabId, ContentParentId(0)); + } + return true; } void TabParent::ActorDestroy(ActorDestroyReason why) { if (sEventCapturer == this) { sEventCapturer = nullptr; @@ -1645,16 +1655,26 @@ TabParent::GetFrom(nsIContent* aContent) nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent); if (!loaderOwner) { return nullptr; } nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader(); return GetFrom(frameLoader); } +/*static*/ TabId +TabParent::GetTabIdFrom(nsIDocShell *docShell) +{ + nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell)); + if (tabChild) { + return static_cast<TabChild*>(tabChild.get())->GetTabId(); + } + return TabId(0); +} + RenderFrameParent* TabParent::GetRenderFrame() { if (ManagedPRenderFrameParent().IsEmpty()) { return nullptr; } return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]); }
--- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -6,16 +6,17 @@ #ifndef mozilla_tabs_TabParent_h #define mozilla_tabs_TabParent_h #include "mozilla/EventForwards.h" #include "mozilla/dom/PBrowserParent.h" #include "mozilla/dom/PFilePickerParent.h" #include "mozilla/dom/TabContext.h" +#include "mozilla/dom/ipc/IdType.h" #include "nsCOMPtr.h" #include "nsIAuthPromptProvider.h" #include "nsIBrowserDOMWindow.h" #include "nsISecureBrowserUI.h" #include "nsITabParent.h" #include "nsIXULBrowserWindow.h" #include "nsWeakReference.h" #include "Units.h" @@ -23,16 +24,17 @@ class nsFrameLoader; class nsIContent; class nsIPrincipal; class nsIURI; class nsIWidget; class nsILoadContext; class CpowHolder; +class nsIDocShell; namespace mozilla { namespace layers { struct FrameMetrics; struct TextureFactoryIdentifier; } @@ -62,17 +64,20 @@ class TabParent : public PBrowserParent typedef mozilla::layout::ScrollingBehavior ScrollingBehavior; virtual ~TabParent(); public: // nsITabParent NS_DECL_NSITABPARENT - TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags); + TabParent(nsIContentParent* aManager, + const TabId& aTabId, + const TabContext& aContext, + uint32_t aChromeFlags); Element* GetOwnerElement() const { return mFrameElement; } void SetOwnerElement(Element* aElement); /** * Get the mozapptype attribute from this TabParent's owner DOM element. */ void GetAppType(nsAString& aOut); @@ -319,27 +324,33 @@ public: static TabParent *GetIMETabParent() { return mIMETabParent; } bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent); bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event); bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event); static TabParent* GetFrom(nsFrameLoader* aFrameLoader); static TabParent* GetFrom(nsIContent* aContent); + static TabId GetTabIdFrom(nsIDocShell* docshell); nsIContentParent* Manager() { return mManager; } /** * Let managees query if Destroy() is already called so they don't send out * messages when the PBrowser actor is being destroyed. */ bool IsDestroyed() const { return mIsDestroyed; } already_AddRefed<nsIWidget> GetWidget() const; + const TabId GetTabId() const + { + return mTabId; + } + protected: bool ReceiveMessage(const nsString& aMessage, bool aSync, const StructuredCloneData* aCloneData, CpowHolder* aCpows, nsIPrincipal* aPrincipal, InfallibleTArray<nsString>* aJSONRetVal = nullptr); @@ -436,14 +447,16 @@ private: // Whether we need to send the offline status to the TabChild // This is true, until the first call of LoadURL bool mSendOfflineStatus; uint32_t mChromeFlags; nsCOMPtr<nsILoadContext> mLoadContext; + + TabId mTabId; }; } // namespace dom } // namespace mozilla #endif
--- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -16,16 +16,17 @@ EXPORTS.mozilla.dom.ipc += [ ] EXPORTS.mozilla.dom += [ 'ContentBridgeChild.h', 'ContentBridgeParent.h', 'ContentChild.h', 'ContentParent.h', 'ContentProcess.h', + 'ContentProcessManager.h', 'CPOWManagerGetter.h', 'CrashReporterChild.h', 'CrashReporterParent.h', 'FilePickerParent.h', 'nsIContentChild.h', 'nsIContentParent.h', 'PermissionMessageUtils.h', 'StructuredCloneUtils.h', @@ -43,16 +44,17 @@ EXPORTS.mozilla += [ UNIFIED_SOURCES += [ 'AppProcessChecker.cpp', 'ColorPickerParent.cpp', 'ContentBridgeChild.cpp', 'ContentBridgeParent.cpp', 'ContentParent.cpp', 'ContentProcess.cpp', + 'ContentProcessManager.cpp', 'CrashReporterParent.cpp', 'FilePickerParent.cpp', 'nsIContentChild.cpp', 'nsIContentParent.cpp', 'PermissionMessageUtils.cpp', 'PreallocatedProcessManager.cpp', 'ProcessPriorityManager.cpp', 'ScreenManagerParent.cpp', @@ -73,16 +75,17 @@ SOURCES += [ 'CrashReporterChild.cpp', ] IPDL_SOURCES += [ 'DOMTypes.ipdlh', 'PBlob.ipdl', 'PBlobStream.ipdl', 'PBrowser.ipdl', + 'PBrowserOrId.ipdlh', 'PColorPicker.ipdl', 'PContent.ipdl', 'PContentBridge.ipdl', 'PContentPermission.ipdlh', 'PContentPermissionRequest.ipdl', 'PCrashReporter.ipdl', 'PCycleCollectWithLogs.ipdl', 'PDocumentRenderer.ipdl',
--- a/dom/ipc/nsIContentChild.cpp +++ b/dom/ipc/nsIContentChild.cpp @@ -45,17 +45,18 @@ nsIContentChild::AllocPJavaScriptChild() bool nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild) { static_cast<JavaScriptChild*>(aChild)->decref(); return true; } PBrowserChild* -nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext, +nsIContentChild::AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, 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. @@ -64,17 +65,17 @@ nsIContentChild::AllocPBrowserChild(cons 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."); } nsRefPtr<TabChild> child = - TabChild::Create(this, tc.GetTabContext(), aChromeFlags); + TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags); // The ref here is released in DeallocPBrowserChild. return child.forget().take(); } bool nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe) {
--- a/dom/ipc/nsIContentChild.h +++ b/dom/ipc/nsIContentChild.h @@ -49,26 +49,28 @@ public: BlobChild* GetOrCreateActorForBlob(File* aBlob); virtual PBlobChild* SendPBlobConstructor( PBlobChild* aActor, const BlobConstructorParams& aParams) = 0; virtual bool SendPBrowserConstructor(PBrowserChild* aActor, + const TabId& aTabId, const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpID, const bool& aIsForApp, const bool& aIsForBrowser) = 0; protected: virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild(); virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*); - virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext, + virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser); virtual bool DeallocPBrowserChild(PBrowserChild*); virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
--- a/dom/ipc/nsIContentParent.cpp +++ b/dom/ipc/nsIContentParent.cpp @@ -19,16 +19,23 @@ #include "JavaScriptParent.h" #include "nsFrameMessageManager.h" #include "nsIJSRuntimeService.h" #include "nsPrintfCString.h" using namespace mozilla::jsipc; +// XXX need another bug to move this to a common header. +#ifdef DISABLE_ASSERTS_FOR_FUZZING +#define ASSERT_UNLESS_FUZZING(...) do { } while (0) +#else +#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__) +#endif + namespace mozilla { namespace dom { nsIContentParent::nsIContentParent() { mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this); } @@ -69,64 +76,70 @@ nsIContentParent::CanOpenBrowser(const I { const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext(); // We don't trust the IPCTabContext we receive from the child, so we'll bail // if we receive an IPCTabContext that's not a PopupIPCTabContext. // (PopupIPCTabContext lets the child process prove that it has access to // the app it's trying to open.) if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) { - NS_ERROR("Unexpected IPCTabContext type. Aborting AllocPBrowserParent."); + ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type. Aborting AllocPBrowserParent."); return false; } const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext(); - TabParent* opener = static_cast<TabParent*>(popupContext.openerParent()); + if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) { + ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type. Aborting AllocPBrowserParent."); + return false; + } + + auto opener = static_cast<TabParent*>(popupContext.opener().get_PBrowserParent()); if (!opener) { - NS_ERROR("Got null opener from child; aborting AllocPBrowserParent."); + ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent."); return false; } // Popup windows of isBrowser frames must be isBrowser if the parent // isBrowser. Allocating a !isBrowser frame with same app ID would allow // the content to access data it's not supposed to. if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) { - NS_ERROR("Child trying to escalate privileges! Aborting AllocPBrowserParent."); + ASSERT_UNLESS_FUZZING("Child trying to escalate privileges! Aborting AllocPBrowserParent."); return false; } MaybeInvalidTabContext tc(aContext); if (!tc.IsValid()) { NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext. (%s) " "Aborting AllocPBrowserParent.", tc.GetInvalidReason()).get()); return false; } return true; } PBrowserParent* -nsIContentParent::AllocPBrowserParent(const IPCTabContext& aContext, +nsIContentParent::AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) { unused << aCpId; unused << aIsForApp; unused << aIsForBrowser; if (!CanOpenBrowser(aContext)) { return nullptr; } MaybeInvalidTabContext tc(aContext); MOZ_ASSERT(tc.IsValid()); - TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags); + TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), aChromeFlags); // We release this ref in DeallocPBrowserParent() NS_ADDREF(parent); return parent; } bool nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
--- a/dom/ipc/nsIContentParent.h +++ b/dom/ipc/nsIContentParent.h @@ -56,33 +56,35 @@ public: virtual bool IsForBrowser() = 0; virtual PBlobParent* SendPBlobConstructor( PBlobParent* aActor, const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0; virtual PBrowserParent* SendPBrowserConstructor( PBrowserParent* actor, + const TabId& aTabId, const IPCTabContext& context, const uint32_t& chromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0; virtual bool IsContentParent() { return false; } ContentParent* AsContentParent(); protected: // methods bool CanOpenBrowser(const IPCTabContext& aContext); protected: // IPDL methods virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent(); virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*); - virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext, + virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId, + const IPCTabContext& aContext, const uint32_t& aChromeFlags, const ContentParentId& aCpId, const bool& aIsForApp, const bool& aIsForBrowser); virtual bool DeallocPBrowserParent(PBrowserParent* frame); virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams);
--- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -21,28 +21,23 @@ include protocol PChannelDiverter; include protocol PBlob; //FIXME: bug #792908 include protocol PFileDescriptorSet; include protocol PRtspController; include protocol PRtspChannel; include URIParams; include InputStreamParams; include NeckoChannelParams; - +include PBrowserOrId; using class IPC::SerializedLoadContext from "SerializedLoadContext.h"; namespace mozilla { namespace net { -union PBrowserOrId { - nullable PBrowser; - uint64_t; -}; - //------------------------------------------------------------------- sync protocol PNecko { manager PContent; manages PHttpChannel; manages PCookieService; manages PWyciwygChannel; manages PFTPChannel;
--- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -22,22 +22,22 @@ class nsICacheEntry; class nsIAssociatedContentSecurity; namespace mozilla { namespace dom{ class TabParent; +class PBrowserOrId; } namespace net { class HttpChannelParentListener; -class PBrowserOrId; class HttpChannelParent : public PHttpChannelParent , public nsIParentRedirectingChannel , public nsIProgressEventSink , public nsIInterfaceRequestor , public ADivertableParentChannel , public nsIAuthPromptProvider , public DisconnectableParent @@ -49,17 +49,17 @@ public: NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSIPARENTCHANNEL NS_DECL_NSIPARENTREDIRECTINGCHANNEL NS_DECL_NSIPROGRESSEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIAUTHPROMPTPROVIDER - HttpChannelParent(const PBrowserOrId& iframeEmbedding, + HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding, nsILoadContext* aLoadContext, PBOverrideStatus aStatus); bool Init(const HttpChannelCreationArgs& aOpenArgs); // ADivertableParentChannel functions. void DivertTo(nsIStreamListener *aListener) MOZ_OVERRIDE; nsresult SuspendForDiversion() MOZ_OVERRIDE;