зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1334716 - Make process selection a service and implementable in JS. r=krizsa
MozReview-Commit-ID: CViRvZB8nKe
This commit is contained in:
Родитель
dbf209197e
Коммит
9fb1ff597d
|
@ -520,6 +520,9 @@
|
||||||
@RESPATH@/components/remotebrowserutils.manifest
|
@RESPATH@/components/remotebrowserutils.manifest
|
||||||
@RESPATH@/components/RemoteWebNavigation.js
|
@RESPATH@/components/RemoteWebNavigation.js
|
||||||
|
|
||||||
|
@RESPATH@/components/ProcessSelector.js
|
||||||
|
@RESPATH@/components/ProcessSelector.manifest
|
||||||
|
|
||||||
@RESPATH@/components/SlowScriptDebug.manifest
|
@RESPATH@/components/SlowScriptDebug.manifest
|
||||||
@RESPATH@/components/SlowScriptDebug.js
|
@RESPATH@/components/SlowScriptDebug.js
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
Cu.import('resource://gre/modules/Services.jsm');
|
||||||
|
|
||||||
|
const BASE_PREF = "dom.ipc.processCount"
|
||||||
|
const PREF_BRANCH = BASE_PREF + ".";
|
||||||
|
|
||||||
|
// Utilities:
|
||||||
|
function getMaxContentParents(processType) {
|
||||||
|
let maxContentParents = -1;
|
||||||
|
try {
|
||||||
|
maxContentParents = Services.prefs.getIntPref(PREF_BRANCH + processType);
|
||||||
|
} catch (e) {
|
||||||
|
// Pref probably didn't exist, get the default number of processes.
|
||||||
|
try {
|
||||||
|
maxContentParents = Services.prefs.getIntPref(BASE_PREF);
|
||||||
|
} catch (e) {
|
||||||
|
// No prefs? That's odd, use only one process.
|
||||||
|
maxContentParents = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxContentParents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fills up aProcesses until max and then selects randomly from the available
|
||||||
|
// ones.
|
||||||
|
function RandomSelector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomSelector.prototype = {
|
||||||
|
classID: Components.ID("{c616fcfd-9737-41f1-aa74-cee72a38f91b}"),
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
|
||||||
|
|
||||||
|
provideProcess(aType, aOpener, aProcesses, aCount) {
|
||||||
|
let maxContentParents = getMaxContentParents(aType);
|
||||||
|
if (aCount < maxContentParents) {
|
||||||
|
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
let startIdx = Math.floor(Math.random() * maxContentParents);
|
||||||
|
let curIdx = startIdx;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (aProcesses[curIdx].opener === aOpener) {
|
||||||
|
return curIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
curIdx = (curIdx + 1) % maxContentParents;
|
||||||
|
} while (curIdx !== startIdx);
|
||||||
|
|
||||||
|
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var components = [RandomSelector];
|
||||||
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
|
@ -0,0 +1,2 @@
|
||||||
|
component {c616fcfd-9737-41f1-aa74-cee72a38f91b} ProcessSelector.js
|
||||||
|
contract @mozilla.org/ipc/processselector;1 {c616fcfd-9737-41f1-aa74-cee72a38f91b}
|
|
@ -401,6 +401,8 @@ EXTRA_COMPONENTS += [
|
||||||
'contentAreaDropListener.manifest',
|
'contentAreaDropListener.manifest',
|
||||||
'messageWakeupService.js',
|
'messageWakeupService.js',
|
||||||
'messageWakeupService.manifest',
|
'messageWakeupService.manifest',
|
||||||
|
'ProcessSelector.js',
|
||||||
|
'ProcessSelector.manifest',
|
||||||
'SlowScriptDebug.js',
|
'SlowScriptDebug.js',
|
||||||
'SlowScriptDebug.manifest',
|
'SlowScriptDebug.manifest',
|
||||||
]
|
]
|
||||||
|
|
|
@ -11,6 +11,7 @@ XPIDL_SOURCES += [
|
||||||
'nsIContentPermissionPrompt.idl',
|
'nsIContentPermissionPrompt.idl',
|
||||||
'nsIContentPrefService.idl',
|
'nsIContentPrefService.idl',
|
||||||
'nsIContentPrefService2.idl',
|
'nsIContentPrefService2.idl',
|
||||||
|
'nsIContentProcess.idl',
|
||||||
'nsIContentURIGrouper.idl',
|
'nsIContentURIGrouper.idl',
|
||||||
'nsIDOMChromeWindow.idl',
|
'nsIDOMChromeWindow.idl',
|
||||||
'nsIDOMClientRect.idl',
|
'nsIDOMClientRect.idl',
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* 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 "nsISupports.idl"
|
||||||
|
|
||||||
|
interface nsIDOMElement;
|
||||||
|
interface nsIMessageSender;
|
||||||
|
interface nsIURI;
|
||||||
|
|
||||||
|
[scriptable, builtinclass, uuid(456f58be-29dd-4973-885b-95aece1c9a8a)]
|
||||||
|
interface nsIContentProcessInfo : nsISupports
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Is this content process alive?
|
||||||
|
*/
|
||||||
|
readonly attribute boolean isAlive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content process's PID.
|
||||||
|
* Throws if the process is not alive.
|
||||||
|
*/
|
||||||
|
readonly attribute int32_t processId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This content process's opener.
|
||||||
|
*/
|
||||||
|
readonly attribute nsIContentProcessInfo opener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The process manager for this ContentParent (so a process message manager
|
||||||
|
* as opposed to a frame message manager.
|
||||||
|
*/
|
||||||
|
readonly attribute nsIMessageSender messageManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
[scriptable, uuid(83ffb063-5f65-4c45-ae07-3f553e0809bb)]
|
||||||
|
interface nsIContentProcessProvider : nsISupports
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return this from provideProcess to create a new process.
|
||||||
|
*/
|
||||||
|
const int32_t NEW_PROCESS = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given aAliveProcesses (with an opener aOpener), choose which process of
|
||||||
|
* aType to use. Return nsIContentProcessProvider.NEW_PROCESS to ask the
|
||||||
|
* caller to create a new content process.
|
||||||
|
*/
|
||||||
|
int32_t provideProcess(in AString aType, in nsIContentProcessInfo aOpener,
|
||||||
|
[array, size_is(aCount)] in nsIContentProcessInfo aAliveProcesses,
|
||||||
|
in uint32_t aCount);
|
||||||
|
};
|
|
@ -112,6 +112,7 @@
|
||||||
#include "nsIAlertsService.h"
|
#include "nsIAlertsService.h"
|
||||||
#include "nsIClipboard.h"
|
#include "nsIClipboard.h"
|
||||||
#include "nsContentPermissionHelper.h"
|
#include "nsContentPermissionHelper.h"
|
||||||
|
#include "nsIContentProcess.h"
|
||||||
#include "nsICycleCollectorListener.h"
|
#include "nsICycleCollectorListener.h"
|
||||||
#include "nsIDocShellTreeOwner.h"
|
#include "nsIDocShellTreeOwner.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
@ -435,6 +436,90 @@ ContentParentsMemoryReporter::CollectReports(
|
||||||
}
|
}
|
||||||
|
|
||||||
nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* ContentParent::sBrowserContentParents;
|
nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* ContentParent::sBrowserContentParents;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ScriptableCPInfo final : public nsIContentProcessInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ScriptableCPInfo(ContentParent* aParent)
|
||||||
|
: mContentParent(aParent)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mContentParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSICONTENTPROCESSINFO
|
||||||
|
|
||||||
|
void ProcessDied()
|
||||||
|
{
|
||||||
|
mContentParent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~ScriptableCPInfo()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mContentParent, "must call ProcessDied");
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentParent* mContentParent;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
ScriptableCPInfo::GetIsAlive(bool* aIsAlive)
|
||||||
|
{
|
||||||
|
*aIsAlive = mContentParent != nullptr;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
ScriptableCPInfo::GetProcessId(int32_t* aPID)
|
||||||
|
{
|
||||||
|
if (!mContentParent) {
|
||||||
|
*aPID = -1;
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aPID = mContentParent->Pid();
|
||||||
|
if (*aPID == -1) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
ScriptableCPInfo::GetOpener(nsIContentProcessInfo** aInfo)
|
||||||
|
{
|
||||||
|
*aInfo = nullptr;
|
||||||
|
if (!mContentParent) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContentParent* opener = mContentParent->Opener()) {
|
||||||
|
nsCOMPtr<nsIContentProcessInfo> info = opener->ScriptableHelper();
|
||||||
|
info.forget(aInfo);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
ScriptableCPInfo::GetMessageManager(nsIMessageSender** aMessenger)
|
||||||
|
{
|
||||||
|
*aMessenger = nullptr;
|
||||||
|
if (!mContentParent) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIMessageSender> manager = mContentParent->GetMessageManager();
|
||||||
|
manager.forget(aMessenger);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
nsTArray<ContentParent*>* ContentParent::sPrivateContent;
|
nsTArray<ContentParent*>* ContentParent::sPrivateContent;
|
||||||
StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
|
StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
|
||||||
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
|
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
|
||||||
|
@ -697,37 +782,64 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
||||||
ContentParent* aOpener)
|
ContentParent* aOpener)
|
||||||
{
|
{
|
||||||
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
|
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
|
||||||
|
|
||||||
uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
|
uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
|
||||||
|
|
||||||
RefPtr<ContentParent> p;
|
|
||||||
if (contentParents.Length() >= maxContentParents) {
|
|
||||||
// We never want to re-use Large-Allocation processes.
|
|
||||||
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||||
|
// We never want to re-use Large-Allocation processes.
|
||||||
|
if (contentParents.Length() >= maxContentParents) {
|
||||||
return GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
return GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||||
aPriority,
|
aPriority,
|
||||||
aOpener);
|
aOpener);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
nsTArray<nsIContentProcessInfo*> infos(contentParents.Length());
|
||||||
|
for (auto* cp : contentParents) {
|
||||||
|
infos.AppendElement(cp->mScriptableHelper);
|
||||||
|
}
|
||||||
|
|
||||||
if ((p = RandomSelect(contentParents, aOpener, maxContentParents))) {
|
nsCOMPtr<nsIContentProcessProvider> cpp =
|
||||||
return p.forget();
|
do_GetService("@mozilla.org/ipc/processselector;1");
|
||||||
|
nsIContentProcessInfo* openerInfo = aOpener ? aOpener->mScriptableHelper.get() : nullptr;
|
||||||
|
int32_t index;
|
||||||
|
if (cpp &&
|
||||||
|
NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, openerInfo,
|
||||||
|
infos.Elements(), infos.Length(),
|
||||||
|
&index))) {
|
||||||
|
// If the provider returned an existing ContentParent, use that one.
|
||||||
|
if (0 <= index && static_cast<uint32_t>(index) <= maxContentParents) {
|
||||||
|
RefPtr<ContentParent> retval = contentParents[index];
|
||||||
|
return retval.forget();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If there was a problem with the JS chooser, fall back to a random
|
||||||
|
// selection.
|
||||||
|
NS_WARNING("nsIContentProcessProvider failed to return a process");
|
||||||
|
RefPtr<ContentParent> random;
|
||||||
|
if (contentParents.Length() >= maxContentParents &&
|
||||||
|
(random = RandomSelect(contentParents, aOpener, maxContentParents))) {
|
||||||
|
return random.forget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to take the preallocated process only for the default process type.
|
// Try to take the preallocated process only for the default process type.
|
||||||
if (aRemoteType.Equals(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)) &&
|
RefPtr<ContentParent> p;
|
||||||
|
if (aRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE) &&
|
||||||
(p = PreallocatedProcessManager::Take())) {
|
(p = PreallocatedProcessManager::Take())) {
|
||||||
// For pre-allocated process we have not set the opener yet.
|
// For pre-allocated process we have not set the opener yet.
|
||||||
p->mOpener = aOpener;
|
p->mOpener = aOpener;
|
||||||
} else {
|
contentParents.AppendElement(p);
|
||||||
p = new ContentParent(aOpener, aRemoteType);
|
return p.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new process from scratch.
|
||||||
|
RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType);
|
||||||
|
|
||||||
if (!p->LaunchSubprocess(aPriority)) {
|
if (!p->LaunchSubprocess(aPriority)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->Init();
|
p->Init();
|
||||||
}
|
|
||||||
|
|
||||||
contentParents.AppendElement(p);
|
contentParents.AppendElement(p);
|
||||||
return p.forget();
|
return p.forget();
|
||||||
|
@ -1204,6 +1316,8 @@ ContentParent::Init()
|
||||||
|
|
||||||
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
|
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
|
||||||
gmps->UpdateContentProcessGMPCapabilities();
|
gmps->UpdateContentProcessGMPCapabilities();
|
||||||
|
|
||||||
|
mScriptableHelper = new ScriptableCPInfo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1274,6 +1388,11 @@ ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority)
|
||||||
void
|
void
|
||||||
ContentParent::ShutDownProcess(ShutDownMethod aMethod)
|
ContentParent::ShutDownProcess(ShutDownMethod aMethod)
|
||||||
{
|
{
|
||||||
|
if (mScriptableHelper) {
|
||||||
|
static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
|
||||||
|
mScriptableHelper = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Shutting down by sending a shutdown message works differently than the
|
// Shutting down by sending a shutdown message works differently than the
|
||||||
// other methods. We first call Shutdown() in the child. After the child is
|
// other methods. We first call Shutdown() in the child. After the child is
|
||||||
// ready, it calls FinishShutdown() on us. Then we close the channel.
|
// ready, it calls FinishShutdown() on us. Then we close the channel.
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
|
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
|
||||||
|
|
||||||
class nsConsoleService;
|
class nsConsoleService;
|
||||||
|
class nsIContentProcessInfo;
|
||||||
class nsICycleCollectorLogSink;
|
class nsICycleCollectorLogSink;
|
||||||
class nsIDumpGCAndCCLogsCallback;
|
class nsIDumpGCAndCCLogsCallback;
|
||||||
class nsITabParent;
|
class nsITabParent;
|
||||||
|
@ -371,6 +372,10 @@ public:
|
||||||
{
|
{
|
||||||
return mOpener;
|
return mOpener;
|
||||||
}
|
}
|
||||||
|
nsIContentProcessInfo* ScriptableHelper() const
|
||||||
|
{
|
||||||
|
return mScriptableHelper;
|
||||||
|
}
|
||||||
|
|
||||||
bool NeedsPermissionsUpdate() const
|
bool NeedsPermissionsUpdate() const
|
||||||
{
|
{
|
||||||
|
@ -1173,6 +1178,7 @@ private:
|
||||||
|
|
||||||
RefPtr<nsConsoleService> mConsoleService;
|
RefPtr<nsConsoleService> mConsoleService;
|
||||||
nsConsoleService* GetConsoleService();
|
nsConsoleService* GetConsoleService();
|
||||||
|
nsCOMPtr<nsIContentProcessInfo> mScriptableHelper;
|
||||||
|
|
||||||
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
|
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче