Bug 558184 - Part 8 - Load js plugins in a separate process. r=billm.

Every JS plugin is assigned a unique ID. When an instance of a JS plugin is created the
frame loader that we use to load the plugin's handler URI will create a special
TabContext. This TabContext causes the ContentParent to use the process for this specific
JS plugin (creating one if it hasn't already) when it creates the PBrowser actors.
This causes the iframes for all the instances of a specific JS plugin to be grouped in the
same process.

--HG--
extra : rebase_source : c39560bdf66cda1a005c7b823b3a46e4734878a4
extra : source : 9cba1db527c7eed4371c9f4caf96fd942608cab6
This commit is contained in:
Peter Van der Beken 2017-05-29 12:38:46 +02:00
Родитель f7f426524e
Коммит 2310b3bd39
18 изменённых файлов: 351 добавлений и 115 удалений

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

@ -156,12 +156,14 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersistable)
NS_INTERFACE_MAP_END
nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated)
nsFrameLoader::nsFrameLoader(Element* aOwner, nsPIDOMWindowOuter* aOpener,
bool aNetworkCreated, int32_t aJSPluginID)
: mOwnerContent(aOwner)
, mDetachedSubdocFrame(nullptr)
, mOpener(aOpener)
, mRemoteBrowser(nullptr)
, mChildID(0)
, mJSPluginID(aJSPluginID)
, mEventMode(EVENT_MODE_NORMAL_DISPATCH)
, mBrowserChangingProcessBlockers(nullptr)
, mIsPrerendered(false)
@ -193,7 +195,8 @@ nsFrameLoader::~nsFrameLoader()
}
nsFrameLoader*
nsFrameLoader::Create(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated)
nsFrameLoader::Create(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetworkCreated,
int32_t aJSPluginId)
{
NS_ENSURE_TRUE(aOwner, nullptr);
nsIDocument* doc = aOwner->OwnerDoc();
@ -223,7 +226,7 @@ nsFrameLoader::Create(Element* aOwner, nsPIDOMWindowOuter* aOpener, bool aNetwor
doc->IsStaticDocument()),
nullptr);
return new nsFrameLoader(aOwner, aOpener, aNetworkCreated);
return new nsFrameLoader(aOwner, aOpener, aNetworkCreated, aJSPluginId);
}
NS_IMETHODIMP
@ -314,8 +317,15 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
nsresult rv = CheckURILoad(aURI);
nsresult rv;
// If IsForJSPlugin() returns true then we want to allow the load. We're just
// loading the source for the implementation of the JS plugin from a URI
// that's under our control. We will already have done the security checks for
// loading the plugin content itself in the object/embed loading code.
if (!IsForJSPlugin()) {
rv = CheckURILoad(aURI);
NS_ENSURE_SUCCESS(rv, rv);
}
mURIToLoad = aURI;
rv = doc->InitializeFrameLoader(this);
@ -2246,6 +2256,10 @@ nsFrameLoader::OwnerIsIsolatedMozBrowserFrame()
bool
nsFrameLoader::ShouldUseRemoteProcess()
{
if (IsForJSPlugin()) {
return true;
}
if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
return false;
@ -2910,7 +2924,9 @@ nsFrameLoader::TryRemoteBrowser()
}
// <iframe mozbrowser> gets to skip these checks.
if (!OwnerIsMozBrowserFrame()) {
// iframes for JS plugins also get to skip these checks. We control the URL that gets
// loaded, but the load is triggered from the document containing the plugin.
if (!OwnerIsMozBrowserFrame() && !IsForJSPlugin()) {
if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
// Allow about:addon an exception to this rule so it can load remote
// extension options pages.
@ -3624,6 +3640,11 @@ nsresult
nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
nsIURI* aURI)
{
if (IsForJSPlugin()) {
return aTabContext->SetTabContextForJSPluginFrame(mJSPluginID) ? NS_OK :
NS_ERROR_FAILURE;
}
OriginAttributes attrs;
attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
nsresult rv;

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

@ -26,6 +26,7 @@
#include "nsIWebBrowserPersistable.h"
#include "nsIFrame.h"
#include "nsIGroupedSHistory.h"
#include "nsPluginTags.h"
class nsIURI;
class nsSubDocumentFrame;
@ -79,7 +80,8 @@ class nsFrameLoader final : public nsIFrameLoader,
public:
static nsFrameLoader* Create(mozilla::dom::Element* aOwner,
nsPIDOMWindowOuter* aOpener,
bool aNetworkCreated);
bool aNetworkCreated,
int32_t aJSPluginID = nsFakePluginTag::NOT_JSPLUGIN);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader)
@ -230,7 +232,8 @@ public:
private:
nsFrameLoader(mozilla::dom::Element* aOwner,
nsPIDOMWindowOuter* aOpener,
bool aNetworkCreated);
bool aNetworkCreated,
int32_t aJSPluginID);
~nsFrameLoader();
void SetOwnerContent(mozilla::dom::Element* aContent);
@ -242,6 +245,11 @@ private:
*/
bool IsRemoteFrame();
bool IsForJSPlugin()
{
return mJSPluginID != nsFakePluginTag::NOT_JSPLUGIN;
}
/**
* Is this a frame loader for a bona fide <iframe mozbrowser>?
* <xul:browser> is not a mozbrowser, so this is false for that case.
@ -343,6 +351,8 @@ private:
TabParent* mRemoteBrowser;
uint64_t mChildID;
int32_t mJSPluginID;
// See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically
// forwards some input events to out-of-process content.
uint32_t mEventMode;

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

@ -556,9 +556,9 @@ nsObjectLoadingContent::MakePluginListener()
return true;
}
// Helper to spawn the frameloader and return a pointer to its docshell
already_AddRefed<nsIDocShell>
nsObjectLoadingContent::SetupFrameLoader(nsIURI *aRecursionCheckURI)
// Helper to spawn the frameloader.
void
nsObjectLoadingContent::SetupFrameLoader(int32_t aJSPluginId)
{
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
@ -566,9 +566,18 @@ nsObjectLoadingContent::SetupFrameLoader(nsIURI *aRecursionCheckURI)
mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
/* aOpener = */ nullptr,
mNetworkCreated);
mNetworkCreated, aJSPluginId);
if (!mFrameLoader) {
NS_NOTREACHED("nsFrameLoader::Create failed");
}
}
// Helper to spawn the frameloader and return a pointer to its docshell.
already_AddRefed<nsIDocShell>
nsObjectLoadingContent::SetupDocShell(nsIURI* aRecursionCheckURI)
{
SetupFrameLoader(nsFakePluginTag::NOT_JSPLUGIN);
if (!mFrameLoader) {
return nullptr;
}
@ -2378,6 +2387,23 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
nsCOMPtr<nsIPluginTag> basetag =
nsContentUtils::PluginTagForType(mContentType, false);
nsCOMPtr<nsIFakePluginTag> tag = do_QueryInterface(basetag);
uint32_t id;
if (NS_FAILED(tag->GetId(&id))) {
rv = NS_ERROR_FAILURE;
break;
}
MOZ_ASSERT(id <= PR_INT32_MAX,
"Something went wrong, nsPluginHost::RegisterFakePlugin shouldn't have "
"given out this id.");
SetupFrameLoader(int32_t(id));
if (!mFrameLoader) {
rv = NS_ERROR_FAILURE;
break;
}
nsCOMPtr<nsIURI> handlerURI;
if (tag) {
tag->GetHandlerURI(getter_AddRefs(handlerURI));
@ -2389,35 +2415,11 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
break;
}
nsCOMPtr<nsIDocShell> docShell = SetupFrameLoader(handlerURI);
if (!docShell) {
rv = NS_ERROR_FAILURE;
break;
}
nsCString spec;
handlerURI->GetSpec(spec);
LOG(("OBJLC [%p]: Loading fake plugin handler (%s)", this, spec.get()));
// XXX(johns): This and moreso the document case below are
// sidestepping/duplicating nsFrameLoader's LoadURI code,
// which is not great.
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
if (loadInfo) {
loadInfo->SetTriggeringPrincipal(thisContent->NodePrincipal());
nsCOMPtr<nsIURI> referrer;
thisContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
loadInfo->SetReferrer(referrer);
rv = docShell->LoadURI(handlerURI, loadInfo,
nsIWebNavigation::LOAD_FLAGS_NONE, false);
} else {
NS_NOTREACHED("CreateLoadInfo failed");
rv = NS_ERROR_FAILURE;
}
rv = mFrameLoader->LoadURI(handlerURI);
if (NS_FAILED(rv)) {
LOG(("OBJLC [%p]: LoadURI() failed for fake handler", this));
mFrameLoader->Destroy();
@ -2435,7 +2437,7 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
break;
}
nsCOMPtr<nsIDocShell> docShell = SetupFrameLoader(mURI);
nsCOMPtr<nsIDocShell> docShell = SetupDocShell(mURI);
if (!docShell) {
rv = NS_ERROR_FAILURE;
break;
@ -3122,6 +3124,12 @@ nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner)
mIsStopping = true;
RefPtr<nsPluginInstanceOwner> kungFuDeathGrip(aInstanceOwner);
if (mType == eType_FakePlugin) {
if (mFrameLoader) {
mFrameLoader->Destroy();
mFrameLoader = nullptr;
}
} else {
RefPtr<nsNPAPIPluginInstance> inst;
aInstanceOwner->GetInstance(getter_AddRefs(inst));
if (inst) {
@ -3133,6 +3141,7 @@ nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner)
NS_ASSERTION(pluginHost, "No plugin host?");
pluginHost->StopPluginInstance(inst);
}
}
aInstanceOwner->Destroy();

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

@ -531,13 +531,15 @@ class nsObjectLoadingContent : public nsImageLoadingContent
*/
bool MakePluginListener();
void SetupFrameLoader(int32_t aJSPluginId);
/**
* Helper to spawn mFrameLoader and return a pointer to its docshell
*
* @param aURI URI we intend to load for the recursive load check (does not
* actually load anything)
*/
already_AddRefed<nsIDocShell> SetupFrameLoader(nsIURI *aRecursionCheckURI);
already_AddRefed<nsIDocShell> SetupDocShell(nsIURI* aRecursionCheckURI);
/**
* Unloads all content and resets the object to a completely unloaded state

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

@ -95,6 +95,7 @@
#include "GeckoProfiler.h"
#include "Units.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "nsIObjectLoadingContent.h"
#ifdef XP_MACOSX
#import <ApplicationServices/ApplicationServices.h>
@ -1282,27 +1283,11 @@ EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
}
bool
EventStateManager::IsRemoteTarget(nsIContent* target) {
if (!target) {
return false;
}
// <browser/iframe remote=true> from XUL
if (target->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::iframe) &&
target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
nsGkAtoms::_true, eIgnoreCase)) {
return true;
}
// <frame/iframe mozbrowser>
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target);
if (browserFrame && browserFrame->GetReallyIsBrowser()) {
EventStateManager::IsRemoteTarget(nsIContent* target)
{
return !!TabParent::GetFrom(target);
}
return false;
}
bool
EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
nsEventStatus *aStatus) {

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

@ -22,6 +22,7 @@ NS_IMPL_ISUPPORTS(ContentBridgeParent,
nsIObserver)
ContentBridgeParent::ContentBridgeParent()
: mIsForJSPlugin(false)
{}
ContentBridgeParent::~ContentBridgeParent()

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

@ -62,6 +62,11 @@ public:
// XXX: do we need this for ContentBridgeParent?
return -1;
}
virtual bool IsForJSPlugin() const override
{
return mIsForJSPlugin;
}
virtual mozilla::ipc::PParentToChildStreamParent*
SendPParentToChildStreamConstructor(mozilla::ipc::PParentToChildStreamParent*) override;
@ -94,6 +99,10 @@ protected:
{
mIsForBrowser = aIsForBrowser;
}
void SetIsForJSPlugin(bool aIsForJSPlugin)
{
mIsForJSPlugin = aIsForJSPlugin;
}
void Close()
{
@ -164,6 +173,7 @@ protected: // members
RefPtr<ContentBridgeParent> mSelfRef;
ContentParentId mChildID;
bool mIsForBrowser;
bool mIsForJSPlugin;
private:
friend class ContentParent;

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

@ -550,6 +550,7 @@ GetTelemetryProcessID(const nsAString& remoteType)
} // anonymous namespace
nsDataHashtable<nsUint32HashKey, ContentParent*>* ContentParent::sJSPluginContentParents;
nsTArray<ContentParent*>* ContentParent::sPrivateContent;
StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
@ -880,6 +881,35 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
return p.forget();
}
/*static*/ already_AddRefed<ContentParent>
ContentParent::GetNewOrUsedJSPluginProcess(uint32_t aPluginID,
const hal::ProcessPriority& aPriority)
{
RefPtr<ContentParent> p;
if (sJSPluginContentParents) {
p = sJSPluginContentParents->Get(aPluginID);
} else {
sJSPluginContentParents =
new nsDataHashtable<nsUint32HashKey, ContentParent*>();
}
if (p) {
return p.forget();
}
p = new ContentParent(aPluginID);
if (!p->LaunchSubprocess(aPriority)) {
return nullptr;
}
p->Init();
sJSPluginContentParents->Put(aPluginID, p);
return p.forget();
}
/*static*/ ProcessPriority
ContentParent::GetInitialProcessPriority(Element* aFrameElement)
{
@ -940,8 +970,14 @@ ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
return IPC_FAIL_NO_REASON(this);
}
if (tc.GetTabContext().IsJSPlugin()) {
cp = GetNewOrUsedJSPluginProcess(tc.GetTabContext().JSPluginId(),
aPriority);
}
else {
cp = GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
aPriority, this);
}
if (!cp) {
*aCpId = 0;
@ -953,6 +989,16 @@ ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
*aIsForBrowser = cp->IsForBrowser();
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
if (cp->IsForJSPlugin()) {
// We group all the iframes for a specific JS plugin into one process, regardless of
// origin. As a consequence that process can't be a child of the content process that
// contains the document with the element loading the plugin. All content processes
// need to be able to communicate with the process for the JS plugin.
cpm->RegisterRemoteFrame(aTabId, ChildID(), aOpenerTabId, aContext, cp->ChildID());
return IPC_OK();
}
// cp was already added to the ContentProcessManager, this just sets the parent ID.
cpm->AddContentProcess(cp, this->ChildID());
if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID()) &&
@ -970,11 +1016,7 @@ ContentParent::RecvBridgeToChildProcess(const ContentParentId& aCpId,
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
ContentParent* cp = cpm->GetContentProcessById(aCpId);
if (cp) {
ContentParentId parentId;
if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
parentId == this->ChildID()) {
if (cp && cp->CanCommunicateWith(ChildID())) {
Endpoint<PContentBridgeParent> parent;
Endpoint<PContentBridgeChild> child;
@ -991,7 +1033,6 @@ ContentParent::RecvBridgeToChildProcess(const ContentParentId& aCpId,
return IPC_OK();
}
}
// You can't bridge to a process you didn't open!
KillHard("BridgeToChildProcess");
@ -1173,15 +1214,21 @@ ContentParent::CreateBrowser(const TabContext& aContext,
RefPtr<nsIContentParent> constructorSender;
if (isInContentProcess) {
MOZ_ASSERT(aContext.IsMozBrowserElement());
MOZ_ASSERT(aContext.IsMozBrowserElement() || aContext.IsJSPlugin());
constructorSender = CreateContentBridgeParent(aContext, initialPriority,
openerTabId, tabId);
} else {
if (aOpenerContentParent) {
constructorSender = aOpenerContentParent;
} else {
if (aContext.IsJSPlugin()) {
constructorSender =
GetNewOrUsedJSPluginProcess(aContext.JSPluginId(),
initialPriority);
} else {
constructorSender =
GetNewOrUsedBrowserProcess(remoteType, initialPriority, nullptr);
}
if (!constructorSender) {
return nullptr;
}
@ -1276,6 +1323,7 @@ ContentParent::CreateContentBridgeParent(const TabContext& aContext,
ContentBridgeParent* parent = ContentBridgeParent::Create(Move(endpoint));
parent->SetChildID(cpId);
parent->SetIsForBrowser(isForBrowser);
parent->SetIsForJSPlugin(aContext.IsJSPlugin());
return parent;
}
@ -1478,7 +1526,15 @@ ContentParent::ShutDownMessageManager()
void
ContentParent::MarkAsTroubled()
{
if (sBrowserContentParents) {
if (IsForJSPlugin()) {
if (sJSPluginContentParents) {
sJSPluginContentParents->Remove(mJSPluginID);
if (!sJSPluginContentParents->Count()) {
delete sJSPluginContentParents;
sJSPluginContentParents = nullptr;
}
}
} else if (sBrowserContentParents) {
nsTArray<ContentParent*>* contentParents =
sBrowserContentParents->Get(mRemoteType);
if (contentParents) {
@ -1593,13 +1649,9 @@ ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId,
// child of it.
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId);
if (ChildID() != aCpId) {
ContentParentId parent;
if (!cpm->GetParentProcessId(contentParent->ChildID(), &parent) ||
ChildID() != parent) {
if (ChildID() != aCpId && !contentParent->CanCommunicateWith(ChildID())) {
return IPC_FAIL_NO_REASON(this);
}
}
// GetTopLevelTabParentByProcessAndTabId will make sure that aTabId
// lives in the process for aCpId.
@ -1614,17 +1666,23 @@ ContentParent::RecvAllocateLayerTreeId(const ContentParentId& aCpId,
}
mozilla::ipc::IPCResult
ContentParent::RecvDeallocateLayerTreeId(const uint64_t& aId)
ContentParent::RecvDeallocateLayerTreeId(const ContentParentId& aCpId,
const uint64_t& aId)
{
GPUProcessManager* gpu = GPUProcessManager::Get();
if (!gpu->IsLayerTreeIdMapped(aId, OtherPid()))
{
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
RefPtr<ContentParent> contentParent = cpm->GetContentProcessById(aCpId);
if (!contentParent->CanCommunicateWith(ChildID())) {
return IPC_FAIL(this, "Spoofed DeallocateLayerTreeId call");
}
if (!gpu->IsLayerTreeIdMapped(aId, contentParent->OtherPid())) {
// You can't deallocate layer tree ids that you didn't allocate
KillHard("DeallocateLayerTreeId");
}
gpu->UnmapLayerTreeId(aId, OtherPid());
gpu->UnmapLayerTreeId(aId, contentParent->OtherPid());
return IPC_OK();
}
@ -1801,6 +1859,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
bool
ContentParent::ShouldKeepProcessAlive() const
{
if (IsForJSPlugin()) {
return true;
}
if (!sBrowserContentParents) {
return false;
}
@ -2033,7 +2095,8 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
}
ContentParent::ContentParent(ContentParent* aOpener,
const nsAString& aRemoteType)
const nsAString& aRemoteType,
int32_t aJSPluginID)
: nsIContentParent()
, mSubprocess(nullptr)
, mLaunchTS(TimeStamp::Now())
@ -2041,6 +2104,7 @@ ContentParent::ContentParent(ContentParent* aOpener,
, mRemoteType(aRemoteType)
, mChildID(gContentChildID++)
, mGeolocationWatchID(-1)
, mJSPluginID(aJSPluginID)
, mNumDestroyingTabs(0)
, mIsAvailable(true)
, mIsAlive(true)
@ -2086,10 +2150,15 @@ ContentParent::~ContentParent()
// We should be removed from all these lists in ActorDestroy.
MOZ_ASSERT(!sPrivateContent || !sPrivateContent->Contains(this));
if (IsForJSPlugin()) {
MOZ_ASSERT(!sJSPluginContentParents ||
!sJSPluginContentParents->Get(mJSPluginID));
} else {
MOZ_ASSERT(!sBrowserContentParents ||
!sBrowserContentParents->Contains(mRemoteType) ||
!sBrowserContentParents->Get(mRemoteType)->Contains(this));
}
}
void
ContentParent::InitInternal(ProcessPriority aInitialPriority,
@ -5212,3 +5281,19 @@ ContentParent::RecvFileCreationRequest(const nsID& aID,
return IPC_OK();
}
bool
ContentParent::CanCommunicateWith(ContentParentId aOtherProcess)
{
// Normally a process can only communicate with its parent, but a JS plugin process can
// communicate with any process.
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
ContentParentId parentId;
if (!cpm->GetParentProcessId(ChildID(), &parentId)) {
return false;
}
if (IsForJSPlugin()) {
return parentId == ContentParentId(0);
}
return parentId == aOtherProcess;
}

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

@ -22,6 +22,7 @@
#include "mozilla/UniquePtr.h"
#include "nsDataHashtable.h"
#include "nsPluginTags.h"
#include "nsFrameMessageManager.h"
#include "nsHashKeys.h"
#include "nsIObserver.h"
@ -177,6 +178,14 @@ public:
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
ContentParent* aOpener = nullptr);
/**
* Get or create a content process for a JS plugin. aPluginID is the id of the JS plugin
* (@see nsFakePlugin::mId). There is a maximum of one process per JS plugin.
*/
static already_AddRefed<ContentParent>
GetNewOrUsedJSPluginProcess(uint32_t aPluginID,
const hal::ProcessPriority& aPriority);
/**
* Get or create a content process for the given TabContext. aFrameElement
* should be the frame/iframe element with which this process will
@ -362,6 +371,10 @@ public:
{
return mIsForBrowser;
}
virtual bool IsForJSPlugin() const override
{
return mJSPluginID != nsFakePluginTag::NOT_JSPLUGIN;
}
GeckoChildProcessHost* Process() const
{
@ -668,6 +681,7 @@ private:
*/
static nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* sBrowserContentParents;
static nsTArray<ContentParent*>* sPrivateContent;
static nsDataHashtable<nsUint32HashKey, ContentParent*> *sJSPluginContentParents;
static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
@ -711,8 +725,17 @@ private:
FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
explicit ContentParent(int32_t aPluginID)
: ContentParent(nullptr, EmptyString(), aPluginID)
{}
ContentParent(ContentParent* aOpener,
const nsAString& aRemoteType);
const nsAString& aRemoteType)
: ContentParent(aOpener, aRemoteType, nsFakePluginTag::NOT_JSPLUGIN)
{}
ContentParent(ContentParent* aOpener,
const nsAString& aRemoteType,
int32_t aPluginID);
// Launch the subprocess and associated initialization.
// Returns false if the process fails to start.
@ -1050,7 +1073,8 @@ private:
const TabId& aTabId,
uint64_t* aId) override;
virtual mozilla::ipc::IPCResult RecvDeallocateLayerTreeId(const uint64_t& aId) override;
virtual mozilla::ipc::IPCResult RecvDeallocateLayerTreeId(const ContentParentId& aCpId,
const uint64_t& aId) override;
virtual mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
@ -1153,6 +1177,8 @@ public:
const bool& aMinimizeMemoryUsage,
const MaybeFileDesc& aDMDFile) override;
bool CanCommunicateWith(ContentParentId aOtherProcess);
private:
// If you add strong pointers to cycle collected objects here, be sure to
@ -1168,6 +1194,12 @@ private:
ContentParentId mChildID;
int32_t mGeolocationWatchID;
// This contains the id for the JS plugin (@see nsFakePluginTag) if this is the
// ContentParent for a process containing iframes for that JS plugin.
// If this is not a ContentParent for a JS plugin then it contains the value
// nsFakePluginTag::NOT_JSPLUGIN.
int32_t mJSPluginID;
nsCString mKillHardAnnotation;
// After we initiate shutdown, we also start a timer to ensure

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

@ -846,7 +846,7 @@ parent:
// Tell the compositor to allocate a layer tree id for nested remote mozbrowsers.
sync AllocateLayerTreeId(ContentParentId cpId, TabId tabId)
returns (uint64_t id);
async DeallocateLayerTreeId(uint64_t id);
async DeallocateLayerTreeId(ContentParentId cpId, uint64_t id);
/**
* Notifies the parent about a recording device is starting or shutdown.

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

@ -56,6 +56,11 @@ struct FrameIPCTabContext
UIStateChangeType showFocusRings;
};
struct JSPluginFrameIPCTabContext
{
uint32_t jsPluginId;
};
// XXXcatalinb: This is only used by ServiceWorkerClients::OpenWindow.
// Because service workers don't have an associated TabChild
// we can't satisfy the security constraints on b2g. As such, the parent
@ -74,6 +79,7 @@ union IPCTabContext
{
PopupIPCTabContext;
FrameIPCTabContext;
JSPluginFrameIPCTabContext;
UnsafeIPCTabContext;
};

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

@ -23,7 +23,7 @@ TabContext::TabContext()
: mIsPrerendered(false)
, mInitialized(false)
, mIsMozBrowserElement(false)
, mOriginAttributes()
, mJSPluginID(-1)
, mShowAccelerators(UIStateChangeType_NoChange)
, mShowFocusRings(UIStateChangeType_NoChange)
{
@ -47,6 +47,18 @@ TabContext::IsMozBrowser() const
return IsMozBrowserElement();
}
bool
TabContext::IsJSPlugin() const
{
return mJSPluginID >= 0;
}
int32_t
TabContext::JSPluginId() const
{
return mJSPluginID;
}
bool
TabContext::SetTabContext(const TabContext& aContext)
{
@ -127,9 +139,23 @@ TabContext::SetTabContext(bool aIsMozBrowserElement,
return true;
}
bool
TabContext::SetTabContextForJSPluginFrame(int32_t aJSPluginID)
{
NS_ENSURE_FALSE(mInitialized, false);
mInitialized = true;
mJSPluginID = aJSPluginID;
return true;
}
IPCTabContext
TabContext::AsIPCTabContext() const
{
if (IsJSPlugin()) {
return IPCTabContext(JSPluginFrameIPCTabContext(mJSPluginID));
}
return IPCTabContext(FrameIPCTabContext(mOriginAttributes,
mIsMozBrowserElement,
mIsPrerendered,
@ -143,6 +169,7 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
{
bool isMozBrowserElement = false;
bool isPrerendered = false;
int32_t jsPluginId = -1;
OriginAttributes originAttributes;
nsAutoString presentationURL;
UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
@ -195,6 +222,13 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
originAttributes = context->mOriginAttributes;
break;
}
case IPCTabContext::TJSPluginFrameIPCTabContext: {
const JSPluginFrameIPCTabContext &ipcContext =
aParams.get_JSPluginFrameIPCTabContext();
jsPluginId = ipcContext.jsPluginId();
break;
}
case IPCTabContext::TFrameIPCTabContext: {
const FrameIPCTabContext &ipcContext =
aParams.get_FrameIPCTabContext();
@ -229,12 +263,16 @@ MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
}
bool rv;
if (jsPluginId >= 0) {
rv = mTabContext.SetTabContextForJSPluginFrame(jsPluginId);
} else {
rv = mTabContext.SetTabContext(isMozBrowserElement,
isPrerendered,
showAccelerators,
showFocusRings,
originAttributes,
presentationURL);
}
if (!rv) {
mInvalidReason = "Couldn't initialize TabContext.";
}

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

@ -63,6 +63,9 @@ public:
*/
bool IsMozBrowser() const;
bool IsJSPlugin() const;
int32_t JSPluginId() const;
/**
* OriginAttributesRef() returns the OriginAttributes of this frame to
* the caller. This is used to store any attribute associated with the frame's
@ -124,6 +127,14 @@ protected:
*/
bool mIsPrerendered;
/**
* Set this TabContext to be for a JS plugin. aPluginID is the id of the JS plugin
* (@see nsFakePlugin::mId).
* As with the other protected mutator methods, this lets you modify a TabContext once.
* (@see TabContext::SetTabContext above for more details).
*/
bool SetTabContextForJSPluginFrame(int32_t aJSPluginID);
private:
/**
* Has this TabContext been initialized? If so, mutator methods will fail.
@ -138,6 +149,8 @@ private:
*/
bool mIsMozBrowserElement;
int32_t mJSPluginID;
/**
* OriginAttributes of the top level tab docShell
*/
@ -183,6 +196,12 @@ public:
aOriginAttributes,
aPresentationURL);
}
bool SetTabContextForJSPluginFrame(uint32_t aJSPluginID)
{
return TabContext::SetTabContextForJSPluginFrame(aJSPluginID);
}
};
/**

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

@ -61,6 +61,7 @@ public:
virtual ContentParentId ChildID() const = 0;
virtual bool IsForBrowser() const = 0;
virtual bool IsForJSPlugin() const = 0;
virtual mozilla::ipc::PIPCBlobInputStreamParent*
SendPIPCBlobInputStreamConstructor(mozilla::ipc::PIPCBlobInputStreamParent* aActor,

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

@ -73,4 +73,9 @@ interface nsIFakePluginTag : nsIPluginTag
// plugin. Note that the original data/src value for the plugin is not loaded
// and will need to be requested by the handler via XHR or similar if desired.
readonly attribute nsIURI handlerURI;
/**
* A unique id for this JS-implemented plugin. 0 is a valid id.
*/
readonly attribute unsigned long id;
};

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

@ -864,6 +864,7 @@ nsresult
nsFakePluginTag::Create(const FakePluginTagInit& aInitDictionary,
nsFakePluginTag** aPluginTag)
{
NS_ENSURE_TRUE(sNextId <= PR_INT32_MAX, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(!aInitDictionary.mMimeEntries.IsEmpty(), NS_ERROR_INVALID_ARG);
RefPtr<nsFakePluginTag> tag = new nsFakePluginTag();
@ -1059,3 +1060,10 @@ nsFakePluginTag::GetLoaded(bool* ret)
*ret = true;
return NS_OK;
}
NS_IMETHODIMP
nsFakePluginTag::GetId(uint32_t* aId)
{
*aId = mId;
return NS_OK;
}

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

@ -229,6 +229,8 @@ public:
uint32_t Id() const { return mId; }
static const int32_t NOT_JSPLUGIN = -1;
private:
nsFakePluginTag();
virtual ~nsFakePluginTag();
@ -237,6 +239,7 @@ private:
// nsPluginHost::RegisterFakePlugin assigns a new id. The id is transferred
// through IPC when getting the list of JS-implemented plugins from child
// processes, so it should be consistent across processes.
// 0 is a valid id.
uint32_t mId;
// The URI of the handler for our fake plugin.

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

@ -245,7 +245,8 @@ RenderFrameParent::ActorDestroy(ActorDestroyReason why)
if (XRE_IsParentProcess()) {
GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, OtherPid());
} else if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->SendDeallocateLayerTreeId(mLayersId);
TabParent* browser = TabParent::GetFrom(mFrameLoader);
ContentChild::GetSingleton()->SendDeallocateLayerTreeId(browser->Manager()->ChildID(), mLayersId);
}
}