mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Backed out 2 changesets (bug 1731792) for causing mochitest failures.
Backed out changeset 44c28a29bbd8 (bug 1731792) Backed out changeset 51bdb1d4baab (bug 1731792)
This commit is contained in:
parent
2248ff6da9
commit
24d8b4f45f
@ -1714,7 +1714,7 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Clear() {
|
||||
// When this PendingRemotenessChange was created, it was given a
|
||||
// `mContentParent`.
|
||||
if (mContentParent) {
|
||||
mContentParent->RemoveKeepAlive(mTarget->BrowserId());
|
||||
mContentParent->RemoveKeepAlive();
|
||||
mContentParent = nullptr;
|
||||
}
|
||||
|
||||
@ -1870,7 +1870,7 @@ CanonicalBrowsingContext::ChangeRemoteness(
|
||||
// Switching to local, so we don't need to create a new process, and will
|
||||
// instead use our embedder process.
|
||||
change->mContentParent = embedderBrowser->Manager();
|
||||
change->mContentParent->AddKeepAlive(BrowserId());
|
||||
change->mContentParent->AddKeepAlive();
|
||||
change->ProcessLaunched();
|
||||
return promise.forget();
|
||||
}
|
||||
@ -1898,7 +1898,6 @@ CanonicalBrowsingContext::ChangeRemoteness(
|
||||
change->mContentParent = ContentParent::GetNewOrUsedLaunchingBrowserProcess(
|
||||
/* aRemoteType = */ aOptions.mRemoteType,
|
||||
/* aGroup = */ finalGroup,
|
||||
/* aBrowserId */ BrowserId(),
|
||||
/* aPriority = */ hal::PROCESS_PRIORITY_FOREGROUND,
|
||||
/* aPreferUsed = */ preferUsed);
|
||||
if (!change->mContentParent) {
|
||||
@ -1909,7 +1908,7 @@ CanonicalBrowsingContext::ChangeRemoteness(
|
||||
// Add a KeepAlive used by this ContentParent, which will be cleared when
|
||||
// the change is complete. This should prevent the process dying before
|
||||
// we're ready to use it.
|
||||
change->mContentParent->AddKeepAlive(BrowserId());
|
||||
change->mContentParent->AddKeepAlive();
|
||||
if (change->mContentParent->IsLaunching()) {
|
||||
change->mContentParent->WaitForLaunchAsync()->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
|
60
dom/base/ProcessSelector.jsm
Normal file
60
dom/base/ProcessSelector.jsm
Normal file
@ -0,0 +1,60 @@
|
||||
/* 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/. */
|
||||
|
||||
// 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: ChromeUtils.generateQI(["nsIContentProcessProvider"]),
|
||||
|
||||
provideProcess(aType, aProcesses, aMaxCount) {
|
||||
if (aProcesses.length < aMaxCount) {
|
||||
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
}
|
||||
|
||||
return Math.floor(Math.random() * aMaxCount);
|
||||
},
|
||||
};
|
||||
|
||||
// Fills up aProcesses until max and then selects one from the available
|
||||
// ones that host the least number of tabs.
|
||||
function MinTabSelector() {}
|
||||
|
||||
MinTabSelector.prototype = {
|
||||
classID: Components.ID("{2dc08eaf-6eef-4394-b1df-a3a927c1290b}"),
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIContentProcessProvider"]),
|
||||
|
||||
provideProcess(aType, aProcesses, aMaxCount) {
|
||||
let min = Number.MAX_VALUE;
|
||||
let candidate = Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
|
||||
// The reason for not directly using aProcesses.length here is because if
|
||||
// we keep processes alive for testing but want a test to use only single
|
||||
// content process we can just keep relying on dom.ipc.processCount = 1
|
||||
// this way.
|
||||
let numIters = Math.min(aProcesses.length, aMaxCount);
|
||||
|
||||
for (let i = 0; i < numIters; i++) {
|
||||
let process = aProcesses[i];
|
||||
let tabCount = process.tabCount;
|
||||
if (tabCount < min) {
|
||||
min = tabCount;
|
||||
candidate = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If all current processes have at least one tab and we have not yet
|
||||
// reached the maximum, spawn a new process.
|
||||
if (min > 0 && aProcesses.length < aMaxCount) {
|
||||
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
}
|
||||
|
||||
// Otherwise we use candidate.
|
||||
return candidate;
|
||||
},
|
||||
};
|
||||
|
||||
var EXPORTED_SYMBOLS = ["RandomSelector", "MinTabSelector"];
|
@ -13,6 +13,17 @@ Classes = [
|
||||
'jsm': 'resource://gre/modules/ContentAreaDropListener.jsm',
|
||||
'constructor': 'ContentAreaDropListener',
|
||||
},
|
||||
{
|
||||
'cid': '{c616fcfd-9737-41f1-aa74-cee72a38f91b}',
|
||||
'jsm': 'resource://gre/modules/ProcessSelector.jsm',
|
||||
'constructor': 'RandomSelector',
|
||||
},
|
||||
{
|
||||
'cid': '{2dc08eaf-6eef-4394-b1df-a3a927c1290b}',
|
||||
'contract_ids': ['@mozilla.org/ipc/processselector;1'],
|
||||
'jsm': 'resource://gre/modules/ProcessSelector.jsm',
|
||||
'constructor': 'MinTabSelector',
|
||||
},
|
||||
{
|
||||
'cid': '{e740ddb4-18b4-4aac-8ae1-9b0f4320769d}',
|
||||
'contract_ids': ['@mozilla.org/dom/slow-script-debug;1'],
|
||||
|
@ -506,6 +506,7 @@ EXTRA_JS_MODULES += [
|
||||
"DOMRequestHelper.jsm",
|
||||
"IndexedDBHelper.jsm",
|
||||
"LocationHelper.jsm",
|
||||
"ProcessSelector.jsm",
|
||||
"SlowScriptDebug.jsm",
|
||||
]
|
||||
|
||||
|
@ -15,6 +15,7 @@ XPIDL_SOURCES += [
|
||||
"nsIBrowserUsage.idl",
|
||||
"nsIContentPermissionPrompt.idl",
|
||||
"nsIContentPrefService2.idl",
|
||||
"nsIContentProcess.idl",
|
||||
"nsIDOMChromeWindow.idl",
|
||||
"nsIDOMGlobalPropertyInitializer.idl",
|
||||
"nsIDOMWindow.idl",
|
||||
|
51
dom/interfaces/base/nsIContentProcess.idl
Normal file
51
dom/interfaces/base/nsIContentProcess.idl
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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 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;
|
||||
|
||||
/**
|
||||
* Number of opened tabs living in this content process.
|
||||
*/
|
||||
readonly attribute int32_t tabCount;
|
||||
|
||||
/**
|
||||
* The process manager for this ContentParent (so a process message manager
|
||||
* as opposed to a frame message manager.
|
||||
*/
|
||||
readonly attribute nsISupports 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, 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 AUTF8String aType,
|
||||
in Array<nsIContentProcessInfo> aAliveProcesses,
|
||||
in uint32_t aMaxCount);
|
||||
};
|
@ -250,8 +250,6 @@ BrowserParent::BrowserParent(ContentParent* aManager, const TabId& aTabId,
|
||||
if (aBrowsingContext->Top()->IsPriorityActive()) {
|
||||
ProcessPriorityManager::ActivityChanged(this, true);
|
||||
}
|
||||
|
||||
mManager->AddKeepAlive(aBrowsingContext->BrowserId());
|
||||
}
|
||||
|
||||
BrowserParent::~BrowserParent() = default;
|
||||
@ -644,17 +642,13 @@ void BrowserParent::Destroy() {
|
||||
|
||||
mIsDestroyed = true;
|
||||
|
||||
if (CanSend()) {
|
||||
Manager()->RemoveKeepAlive(mBrowsingContext->BrowserId());
|
||||
}
|
||||
|
||||
Manager()->NotifyTabDestroying();
|
||||
|
||||
// This `AddKeepAlive` will be cleared if `mMarkedDestroying` is set in
|
||||
// `ActorDestroy`. Out of caution, we don't add the `KeepAlive` if our IPC
|
||||
// actor has somehow already been destroyed, as that would mean `ActorDestroy`
|
||||
// won't be called.
|
||||
if (CanSend()) {
|
||||
if (CanRecv()) {
|
||||
mBrowsingContext->Group()->AddKeepAlive();
|
||||
}
|
||||
|
||||
@ -681,13 +675,12 @@ mozilla::ipc::IPCResult BrowserParent::RecvEnsureLayersConnected(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void BrowserParent::ActorDestroy(ActorDestroyReason why) {
|
||||
if (!mIsDestroyed) {
|
||||
Manager()->RemoveKeepAlive(mBrowsingContext->BrowserId());
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::Recv__delete__() {
|
||||
Manager()->NotifyTabDestroyed(mTabId, mMarkedDestroying);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void BrowserParent::ActorDestroy(ActorDestroyReason why) {
|
||||
ContentProcessManager::GetSingleton()->UnregisterRemoteFrame(mTabId);
|
||||
|
||||
if (mRemoteLayerTreeOwner.IsInitialized()) {
|
||||
|
@ -721,6 +721,8 @@ class BrowserParent final : public PBrowserParent,
|
||||
const nsString& aMessage, bool aSync, ipc::StructuredCloneData* aData,
|
||||
nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
|
||||
|
||||
virtual mozilla::ipc::IPCResult Recv__delete__() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents();
|
||||
|
@ -194,6 +194,7 @@
|
||||
#include "nsICaptivePortalService.h"
|
||||
#include "nsICertOverrideService.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsIContentProcess.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsICookie.h"
|
||||
#include "nsICrashService.h"
|
||||
@ -529,6 +530,70 @@ uint64_t ComputeLoadedOriginHash(nsIPrincipal* aPrincipal) {
|
||||
return ((uint64_t)originNoSuffix) << 32 | originSuffix;
|
||||
}
|
||||
|
||||
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::GetTabCount(int32_t* aTabCount) {
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
*aTabCount = cpm->GetBrowserParentCountByProcessId(mContentParent->ChildID());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) {
|
||||
*aMessenger = nullptr;
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
RefPtr<ProcessMessageManager> manager = mContentParent->GetMessageManager();
|
||||
manager.forget(aMessenger);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ProcessID GetTelemetryProcessID(const nsACString& remoteType) {
|
||||
// OOP WebExtensions run in a content process.
|
||||
// For Telemetry though we want to break out collected data from the
|
||||
@ -786,6 +851,39 @@ void ContentParent::ReleaseCachedProcesses() {
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
already_AddRefed<ContentParent> ContentParent::MinTabSelect(
|
||||
const nsTArray<ContentParent*>& aContentParents,
|
||||
int32_t aMaxContentParents) {
|
||||
uint32_t maxSelectable =
|
||||
std::min(static_cast<uint32_t>(aContentParents.Length()),
|
||||
static_cast<uint32_t>(aMaxContentParents));
|
||||
uint32_t min = INT_MAX;
|
||||
RefPtr<ContentParent> candidate;
|
||||
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
|
||||
|
||||
for (uint32_t i = 0; i < maxSelectable; i++) {
|
||||
ContentParent* p = aContentParents[i];
|
||||
MOZ_DIAGNOSTIC_ASSERT(!p->IsDead());
|
||||
|
||||
uint32_t tabCount = cpm->GetBrowserParentCountByProcessId(p->ChildID());
|
||||
if (tabCount < min) {
|
||||
candidate = p;
|
||||
min = tabCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If all current processes have at least one tab and we have not yet reached
|
||||
// the maximum, use a new process.
|
||||
if (min > 0 &&
|
||||
aContentParents.Length() < static_cast<uint32_t>(aMaxContentParents)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Otherwise we return candidate.
|
||||
return candidate.forget();
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIPrincipal> CreateRemoteTypeIsolationPrincipal(
|
||||
const nsACString& aRemoteType) {
|
||||
if ((RemoteTypePrefix(aRemoteType) != FISSION_WEB_REMOTE_TYPE) &&
|
||||
@ -807,64 +905,59 @@ static already_AddRefed<nsIPrincipal> CreateRemoteTypeIsolationPrincipal(
|
||||
/*static*/
|
||||
already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess(
|
||||
const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
|
||||
uint32_t aMaxContentParents, uint64_t aBrowserId, bool aPreferUsed,
|
||||
ProcessPriority aPriority) {
|
||||
uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority) {
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
AutoRestore ar(sInProcessSelector);
|
||||
sInProcessSelector = true;
|
||||
#endif
|
||||
|
||||
if (!StaticPrefs::dom_ipc_disableContentProcessReuse() &&
|
||||
!aContentParents.IsEmpty() &&
|
||||
aRemoteType != LARGE_ALLOCATION_REMOTE_TYPE) {
|
||||
// Collect a list of eligible content processes which are tied for the
|
||||
// lowest effective tab count. We only consider at most `aMaxContentParents`
|
||||
// processes even if more are available, in case the process count was
|
||||
// dropped by a test.
|
||||
RefPtr<ContentParent> selected;
|
||||
uint32_t minTabCount = UINT32_MAX;
|
||||
uint32_t processCount =
|
||||
std::min(aMaxContentParents, uint32_t(aContentParents.Length()));
|
||||
for (uint32_t i = 0; i < processCount; ++i) {
|
||||
ContentParent* parent = aContentParents[i];
|
||||
// Determine the effective number of tabs which are loaded in a given
|
||||
// content process, based on the keepalive table. We don't count `0` (as
|
||||
// it doesn't correspond to a tab), and `aBrowserId` (as it corresponds to
|
||||
// this tab) when doing the counts.
|
||||
uint32_t effectiveTabCount = parent->mKeepAlivesByBrowserId.Count();
|
||||
if (parent->mKeepAlivesByBrowserId.Contains(0)) {
|
||||
--effectiveTabCount;
|
||||
}
|
||||
if (parent->mKeepAlivesByBrowserId.Contains(aBrowserId)) {
|
||||
--effectiveTabCount;
|
||||
}
|
||||
if (effectiveTabCount < minTabCount) {
|
||||
minTabCount = effectiveTabCount;
|
||||
selected = parent;
|
||||
}
|
||||
}
|
||||
uint32_t numberOfParents = aContentParents.Length();
|
||||
nsTArray<RefPtr<nsIContentProcessInfo>> infos(numberOfParents);
|
||||
for (auto* cp : aContentParents) {
|
||||
infos.AppendElement(cp->mScriptableHelper);
|
||||
}
|
||||
|
||||
// If every tab has at least one tab (other than our tab, which was excluded
|
||||
// from the count) already loaded in it, prefer creating a new process.
|
||||
if (minTabCount > 0 && !aPreferUsed &&
|
||||
aMaxContentParents > aContentParents.Length()) {
|
||||
selected = nullptr;
|
||||
}
|
||||
if (aPreferUsed && numberOfParents) {
|
||||
// If we prefer re-using existing content processes, we don't want to create
|
||||
// a new process, and instead re-use an existing one, so pretend the process
|
||||
// limit is at the current number of processes.
|
||||
aMaxContentParents = numberOfParents;
|
||||
}
|
||||
|
||||
// If we successfully selected a content process, return it.
|
||||
if (selected) {
|
||||
nsCOMPtr<nsIContentProcessProvider> cpp =
|
||||
do_GetService("@mozilla.org/ipc/processselector;1");
|
||||
int32_t index;
|
||||
if (cpp && NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, infos,
|
||||
aMaxContentParents, &index))) {
|
||||
// If the provider returned an existing ContentParent, use that one.
|
||||
if (0 <= index && static_cast<uint32_t>(index) <= aMaxContentParents) {
|
||||
RefPtr<ContentParent> retval = aContentParents[index];
|
||||
if (profiler_thread_is_being_profiled()) {
|
||||
nsPrintfCString marker("Reused process %" PRIu64,
|
||||
(uint64_t)selected->ChildID());
|
||||
nsPrintfCString marker("Reused process %u",
|
||||
(unsigned int)retval->ChildID());
|
||||
PROFILER_MARKER_TEXT("Process", DOM, {}, marker);
|
||||
}
|
||||
MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
|
||||
("GetUsedProcess: Reused process %p (%" PRIu64 ") for %s",
|
||||
selected.get(), (uint64_t)selected->ChildID(),
|
||||
("GetUsedProcess: Reused process %p (%u) for %s", retval.get(),
|
||||
(unsigned int)retval->ChildID(),
|
||||
PromiseFlatCString(aRemoteType).get()));
|
||||
selected->AssertAlive();
|
||||
selected->StopRecycling();
|
||||
return selected.forget();
|
||||
retval->AssertAlive();
|
||||
retval->StopRecycling();
|
||||
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 ((random = MinTabSelect(aContentParents, aMaxContentParents))) {
|
||||
MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
|
||||
("GetUsedProcess: Reused random process %p (%d) for %s",
|
||||
random.get(), (unsigned int)random->ChildID(),
|
||||
PromiseFlatCString(aRemoteType).get()));
|
||||
random->AssertAlive();
|
||||
random->StopRecycling();
|
||||
return random.forget();
|
||||
}
|
||||
}
|
||||
|
||||
@ -944,7 +1037,7 @@ already_AddRefed<ContentParent> ContentParent::GetUsedBrowserProcess(
|
||||
already_AddRefed<ContentParent>
|
||||
ContentParent::GetNewOrUsedLaunchingBrowserProcess(
|
||||
const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
|
||||
uint64_t aBrowserId, ProcessPriority aPriority, bool aPreferUsed) {
|
||||
ProcessPriority aPriority, bool aPreferUsed) {
|
||||
MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
|
||||
("GetNewOrUsedProcess for type %s",
|
||||
PromiseFlatCString(aRemoteType).get()));
|
||||
@ -973,14 +1066,13 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess(
|
||||
MOZ_LOG(ContentParent::GetLog(), LogLevel::Debug,
|
||||
("GetNewOrUsedProcess: returning Large Used process"));
|
||||
return GetNewOrUsedLaunchingBrowserProcess(DEFAULT_REMOTE_TYPE, aGroup,
|
||||
aBrowserId, aPriority,
|
||||
aPriority,
|
||||
/*aPreferUsed =*/false);
|
||||
}
|
||||
|
||||
// Let's try and reuse an existing process.
|
||||
contentParent =
|
||||
GetUsedBrowserProcess(aRemoteType, contentParents, maxContentParents,
|
||||
aBrowserId, aPreferUsed, aPriority);
|
||||
contentParent = GetUsedBrowserProcess(
|
||||
aRemoteType, contentParents, maxContentParents, aPreferUsed, aPriority);
|
||||
|
||||
if (!contentParent) {
|
||||
// No reusable process. Let's create and launch one.
|
||||
@ -1023,12 +1115,11 @@ ContentParent::GetNewOrUsedLaunchingBrowserProcess(
|
||||
RefPtr<ContentParent::LaunchPromise>
|
||||
ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
|
||||
BrowsingContextGroup* aGroup,
|
||||
uint64_t aBrowserId,
|
||||
ProcessPriority aPriority,
|
||||
bool aPreferUsed) {
|
||||
// Obtain a `ContentParent` launched asynchronously.
|
||||
RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
|
||||
aRemoteType, aGroup, aBrowserId, aPriority, aPreferUsed);
|
||||
aRemoteType, aGroup, aPriority, aPreferUsed);
|
||||
if (!contentParent) {
|
||||
// In case of launch error, stop here.
|
||||
return LaunchPromise::CreateAndReject(LaunchError(), __func__);
|
||||
@ -1039,9 +1130,9 @@ ContentParent::GetNewOrUsedBrowserProcessAsync(const nsACString& aRemoteType,
|
||||
/*static*/
|
||||
already_AddRefed<ContentParent> ContentParent::GetNewOrUsedBrowserProcess(
|
||||
const nsACString& aRemoteType, BrowsingContextGroup* aGroup,
|
||||
uint64_t aBrowserId, ProcessPriority aPriority, bool aPreferUsed) {
|
||||
ProcessPriority aPriority, bool aPreferUsed) {
|
||||
RefPtr<ContentParent> contentParent = GetNewOrUsedLaunchingBrowserProcess(
|
||||
aRemoteType, aGroup, aBrowserId, aPriority, aPreferUsed);
|
||||
aRemoteType, aGroup, aPriority, aPreferUsed);
|
||||
if (!contentParent || !contentParent->WaitForLaunchSync(aPriority)) {
|
||||
// In case of launch error, stop here.
|
||||
return nullptr;
|
||||
@ -1407,8 +1498,7 @@ already_AddRefed<RemoteBrowser> ContentParent::CreateBrowser(
|
||||
aContext.JSPluginId(), PROCESS_PRIORITY_FOREGROUND);
|
||||
} else {
|
||||
constructorSender = GetNewOrUsedBrowserProcess(
|
||||
remoteType, aBrowsingContext->Group(), aBrowsingContext->BrowserId(),
|
||||
PROCESS_PRIORITY_FOREGROUND);
|
||||
remoteType, aBrowsingContext->Group(), PROCESS_PRIORITY_FOREGROUND);
|
||||
}
|
||||
if (!constructorSender) {
|
||||
return nullptr;
|
||||
@ -1866,6 +1956,11 @@ void ContentParent::MarkAsDead() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mScriptableHelper) {
|
||||
static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
|
||||
mScriptableHelper = nullptr;
|
||||
}
|
||||
|
||||
mLifecycleState = LifecycleState::DEAD;
|
||||
}
|
||||
|
||||
@ -2145,7 +2240,7 @@ bool ContentParent::ShouldKeepProcessAlive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mKeepAlivesByBrowserId.IsEmpty()) {
|
||||
if (mNumKeepaliveCalls > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2216,21 +2311,14 @@ void ContentParent::NotifyTabDestroying() {
|
||||
#endif // !defined(MOZ_WIDGET_ANDROID)
|
||||
}
|
||||
|
||||
void ContentParent::AddKeepAlive(uint64_t aBrowserId) {
|
||||
void ContentParent::AddKeepAlive() {
|
||||
// Something wants to keep this content process alive.
|
||||
auto& numKeepaliveCalls = mKeepAlivesByBrowserId.LookupOrInsert(aBrowserId);
|
||||
++numKeepaliveCalls;
|
||||
++mNumKeepaliveCalls;
|
||||
}
|
||||
|
||||
void ContentParent::RemoveKeepAlive(uint64_t aBrowserId) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mKeepAlivesByBrowserId.IsEmpty());
|
||||
|
||||
auto entry = mKeepAlivesByBrowserId.Lookup(aBrowserId);
|
||||
MOZ_DIAGNOSTIC_ASSERT(entry && entry.Data() > 0);
|
||||
--entry.Data();
|
||||
if (entry.Data() == 0) {
|
||||
entry.Remove();
|
||||
}
|
||||
void ContentParent::RemoveKeepAlive() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mNumKeepaliveCalls > 0);
|
||||
--mNumKeepaliveCalls;
|
||||
|
||||
MaybeBeginShutDown();
|
||||
}
|
||||
@ -2654,6 +2742,7 @@ ContentParent::ContentParent(const nsACString& aRemoteType, int32_t aJSPluginID)
|
||||
mJSPluginID(aJSPluginID),
|
||||
mRemoteWorkerActorData("ContentParent::mRemoteWorkerActorData"),
|
||||
mNumDestroyingTabs(0),
|
||||
mNumKeepaliveCalls(0),
|
||||
mLifecycleState(LifecycleState::LAUNCHING),
|
||||
mIsForBrowser(!mRemoteType.IsEmpty()),
|
||||
mCalledClose(false),
|
||||
@ -2695,6 +2784,10 @@ ContentParent::ContentParent(const nsACString& aRemoteType, int32_t aJSPluginID)
|
||||
("CreateSubprocess: ContentParent %p mSubprocess %p handle %" PRIuPTR,
|
||||
this, mSubprocess,
|
||||
mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
|
||||
|
||||
// This is safe to do in the constructor, as it doesn't take a strong
|
||||
// reference.
|
||||
mScriptableHelper = new ScriptableCPInfo(this);
|
||||
}
|
||||
|
||||
ContentParent::~ContentParent() {
|
||||
@ -2724,6 +2817,13 @@ ContentParent::~ContentParent() {
|
||||
mSubprocess ? (uintptr_t)mSubprocess->GetChildProcessHandle() : -1));
|
||||
mSubprocess->Destroy();
|
||||
}
|
||||
|
||||
// Make sure to clear the connection from `mScriptableHelper` if it hasn't
|
||||
// been cleared yet.
|
||||
if (mScriptableHelper) {
|
||||
static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
|
||||
mScriptableHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
|
||||
|
@ -53,6 +53,7 @@
|
||||
#define CHILD_PROCESS_SHUTDOWN_MESSAGE u"child-process-shutdown"_ns
|
||||
|
||||
class nsConsoleService;
|
||||
class nsIContentProcessInfo;
|
||||
class nsICycleCollectorLogSink;
|
||||
class nsIDumpGCAndCCLogsCallback;
|
||||
class nsIRemoteTab;
|
||||
@ -175,6 +176,15 @@ class ContentParent final
|
||||
static void LogAndAssertFailedPrincipalValidationInfo(
|
||||
nsIPrincipal* aPrincipal, const char* aMethod);
|
||||
|
||||
/**
|
||||
* Picks a random content parent from |aContentParents| respecting the index
|
||||
* limit set by |aMaxContentParents|.
|
||||
* Returns null if non available.
|
||||
*/
|
||||
static already_AddRefed<ContentParent> MinTabSelect(
|
||||
const nsTArray<ContentParent*>& aContentParents,
|
||||
int32_t maxContentParents);
|
||||
|
||||
/**
|
||||
* Get or create a content process for:
|
||||
* 1. browser iframe
|
||||
@ -183,13 +193,11 @@ class ContentParent final
|
||||
*/
|
||||
static RefPtr<ContentParent::LaunchPromise> GetNewOrUsedBrowserProcessAsync(
|
||||
const nsACString& aRemoteType, BrowsingContextGroup* aGroup = nullptr,
|
||||
uint64_t aBrowserId = 0,
|
||||
hal::ProcessPriority aPriority =
|
||||
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
|
||||
bool aPreferUsed = false);
|
||||
static already_AddRefed<ContentParent> GetNewOrUsedBrowserProcess(
|
||||
const nsACString& aRemoteType, BrowsingContextGroup* aGroup = nullptr,
|
||||
uint64_t aBrowserId = 0,
|
||||
hal::ProcessPriority aPriority =
|
||||
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
|
||||
bool aPreferUsed = false);
|
||||
@ -206,7 +214,6 @@ class ContentParent final
|
||||
*/
|
||||
static already_AddRefed<ContentParent> GetNewOrUsedLaunchingBrowserProcess(
|
||||
const nsACString& aRemoteType, BrowsingContextGroup* aGroup = nullptr,
|
||||
uint64_t aBrowserId = 0,
|
||||
hal::ProcessPriority aPriority =
|
||||
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
|
||||
bool aPreferUsed = false);
|
||||
@ -366,10 +373,9 @@ class ContentParent final
|
||||
void NotifyTabDestroyed(const TabId& aTabId, bool aNotifiedDestroying);
|
||||
|
||||
// Manage the set of `KeepAlive`s on this ContentParent which are preventing
|
||||
// it from being destroyed. This is keyed by BrowserId to allow it to be used
|
||||
// to assist in process selection.
|
||||
void AddKeepAlive(uint64_t aBrowserId = 0);
|
||||
void RemoveKeepAlive(uint64_t aBrowserId = 0);
|
||||
// it from being destroyed.
|
||||
void AddKeepAlive();
|
||||
void RemoveKeepAlive();
|
||||
|
||||
TestShellParent* CreateTestShell();
|
||||
|
||||
@ -404,6 +410,8 @@ class ContentParent final
|
||||
|
||||
GeckoChildProcessHost* Process() const { return mSubprocess; }
|
||||
|
||||
nsIContentProcessInfo* ScriptableHelper() const { return mScriptableHelper; }
|
||||
|
||||
mozilla::dom::ProcessMessageManager* GetMessageManager() const {
|
||||
return mMessageManager;
|
||||
}
|
||||
@ -1442,8 +1450,7 @@ class ContentParent final
|
||||
// Return an existing ContentParent if possible. Otherwise, `nullptr`.
|
||||
static already_AddRefed<ContentParent> GetUsedBrowserProcess(
|
||||
const nsACString& aRemoteType, nsTArray<ContentParent*>& aContentParents,
|
||||
uint32_t aMaxContentParents, uint64_t aBrowserId, bool aPreferUsed,
|
||||
ProcessPriority aPriority);
|
||||
uint32_t aMaxContentParents, bool aPreferUsed, ProcessPriority aPriority);
|
||||
|
||||
void AddToPool(nsTArray<ContentParent*>&);
|
||||
void RemoveFromPool(nsTArray<ContentParent*>&);
|
||||
@ -1519,10 +1526,7 @@ class ContentParent final
|
||||
// NotifyTabDestroying() but not called NotifyTabDestroyed().
|
||||
int32_t mNumDestroyingTabs;
|
||||
|
||||
// The number of KeepAlive calls for this ContentParent, keyed by BrowserId.
|
||||
// This is used to track the number of tabs which are actively being hosted by
|
||||
// each ContentParent.
|
||||
nsTHashMap<uint64_t, uint32_t> mKeepAlivesByBrowserId;
|
||||
uint32_t mNumKeepaliveCalls;
|
||||
|
||||
// The process starts in the LAUNCHING state, and transitions to
|
||||
// ALIVE once it can accept IPC messages. It remains ALIVE only
|
||||
@ -1564,6 +1568,7 @@ class ContentParent final
|
||||
|
||||
RefPtr<nsConsoleService> mConsoleService;
|
||||
nsConsoleService* GetConsoleService();
|
||||
nsCOMPtr<nsIContentProcessInfo> mScriptableHelper;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
|
||||
|
||||
|
@ -717,7 +717,6 @@ void RemoteWorkerManager::LaunchNewContentProcess(
|
||||
ContentParent::GetNewOrUsedBrowserProcessAsync(
|
||||
/* aRemoteType = */ remoteType,
|
||||
/* aGroup */ nullptr,
|
||||
/* aBrowserId */ 0,
|
||||
hal::ProcessPriority::PROCESS_PRIORITY_FOREGROUND,
|
||||
/* aPreferUsed */ true)
|
||||
->Then(GetCurrentSerialEventTarget(), __func__,
|
||||
|
@ -35,8 +35,7 @@ ImageCacheKey::ImageCacheKey(nsIURI* aURI, const OriginAttributes& aAttrs,
|
||||
mOriginAttributes(aAttrs),
|
||||
mControlledDocument(GetSpecialCaseDocumentToken(aDocument)),
|
||||
mIsolationKey(GetIsolationKey(aDocument, aURI)),
|
||||
mIsChrome(false),
|
||||
mAppType(GetAppType(aDocument)) {
|
||||
mIsChrome(false) {
|
||||
if (mURI->SchemeIs("chrome")) {
|
||||
mIsChrome = true;
|
||||
}
|
||||
@ -48,8 +47,7 @@ ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
|
||||
mControlledDocument(aOther.mControlledDocument),
|
||||
mIsolationKey(aOther.mIsolationKey),
|
||||
mHash(aOther.mHash),
|
||||
mIsChrome(aOther.mIsChrome),
|
||||
mAppType(aOther.mAppType) {}
|
||||
mIsChrome(aOther.mIsChrome) {}
|
||||
|
||||
ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
|
||||
: mURI(std::move(aOther.mURI)),
|
||||
@ -57,8 +55,7 @@ ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
|
||||
mControlledDocument(aOther.mControlledDocument),
|
||||
mIsolationKey(aOther.mIsolationKey),
|
||||
mHash(aOther.mHash),
|
||||
mIsChrome(aOther.mIsChrome),
|
||||
mAppType(aOther.mAppType) {}
|
||||
mIsChrome(aOther.mIsChrome) {}
|
||||
|
||||
bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const {
|
||||
// Don't share the image cache between a controlled document and anything
|
||||
@ -76,10 +73,6 @@ bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const {
|
||||
if (mOriginAttributes != aOther.mOriginAttributes) {
|
||||
return false;
|
||||
}
|
||||
// Don't share the image cache between two different appTypes
|
||||
if (mAppType != aOther.mAppType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For non-blob URIs, compare the URIs.
|
||||
bool equals = false;
|
||||
@ -103,7 +96,7 @@ void ImageCacheKey::EnsureHash() const {
|
||||
hash = HashString(spec);
|
||||
|
||||
hash = AddToHash(hash, HashString(suffix), HashString(mIsolationKey),
|
||||
HashString(ptr), mAppType);
|
||||
HashString(ptr));
|
||||
mHash.emplace(hash);
|
||||
}
|
||||
|
||||
@ -172,24 +165,5 @@ nsCString ImageCacheKey::GetIsolationKey(Document* aDocument, nsIURI* aURI) {
|
||||
return ""_ns;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsIDocShell::AppType ImageCacheKey::GetAppType(Document* aDocument) {
|
||||
if (!aDocument) {
|
||||
return nsIDocShell::APP_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti = aDocument->GetDocShell();
|
||||
if (!dsti) {
|
||||
return nsIDocShell::APP_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
dsti->GetInProcessRootTreeItem(getter_AddRefs(root));
|
||||
if (nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(root)) {
|
||||
return docShell->GetAppType();
|
||||
}
|
||||
return nsIDocShell::APP_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
@ -71,10 +70,6 @@ class ImageCacheKey final {
|
||||
// document's base domain. This is handled by this method.
|
||||
static nsCString GetIsolationKey(dom::Document* aDocument, nsIURI* aURI);
|
||||
|
||||
// The AppType of the docshell an image is loaded in can influence whether the
|
||||
// image is allowed to load. The specific AppType is fetched by this method.
|
||||
static nsIDocShell::AppType GetAppType(dom::Document* aDocument);
|
||||
|
||||
void EnsureHash() const;
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
@ -83,7 +78,6 @@ class ImageCacheKey final {
|
||||
nsCString mIsolationKey;
|
||||
mutable Maybe<PLDHashNumber> mHash;
|
||||
bool mIsChrome;
|
||||
nsIDocShell::AppType mAppType;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
|
@ -2410,15 +2410,6 @@
|
||||
#endif
|
||||
mirror: always
|
||||
|
||||
# If true, disables non-required re-use of content processes. This can be used
|
||||
# in tests to force a new process to be used whenever a process selection
|
||||
# decision is made. Setting this pref can cause dom.ipc.processCount limits to
|
||||
# be exceeded.
|
||||
- name: dom.ipc.disableContentProcessReuse
|
||||
type: bool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: dom.ipc.tabs.disabled
|
||||
type: bool
|
||||
value: false
|
||||
|
@ -19,6 +19,9 @@ var EXPORTED_SYMBOLS = ["BrowserTestUtils"];
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { ComponentUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/ComponentUtils.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
@ -40,9 +43,32 @@ XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
],
|
||||
});
|
||||
|
||||
const PROCESSSELECTOR_CONTRACTID = "@mozilla.org/ipc/processselector;1";
|
||||
const OUR_PROCESSSELECTOR_CID = Components.ID(
|
||||
"{f9746211-3d53-4465-9aeb-ca0d96de0253}"
|
||||
);
|
||||
const EXISTING_JSID = Cc[PROCESSSELECTOR_CONTRACTID];
|
||||
const DEFAULT_PROCESSSELECTOR_CID = EXISTING_JSID
|
||||
? Components.ID(EXISTING_JSID.number)
|
||||
: null;
|
||||
|
||||
let gListenerId = 0;
|
||||
|
||||
const DISABLE_CONTENT_PROCESS_REUSE_PREF = "dom.ipc.disableContentProcessReuse";
|
||||
// A process selector that always asks for a new process.
|
||||
function NewProcessSelector() {}
|
||||
|
||||
NewProcessSelector.prototype = {
|
||||
classID: OUR_PROCESSSELECTOR_CID,
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIContentProcessProvider"]),
|
||||
|
||||
provideProcess() {
|
||||
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
},
|
||||
};
|
||||
|
||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
let selectorFactory = ComponentUtils._getFactory(NewProcessSelector);
|
||||
registrar.registerFactory(OUR_PROCESSSELECTOR_CID, "", null, selectorFactory);
|
||||
|
||||
const kAboutPageRegistrationContentScript =
|
||||
"chrome://mochikit/content/tests/BrowserTestUtils/content-about-page-utils.js";
|
||||
@ -200,17 +226,19 @@ var BrowserTestUtils = {
|
||||
} = options;
|
||||
|
||||
let promises, tab;
|
||||
let disableReusePrefValue = Services.prefs.getBoolPref(
|
||||
DISABLE_CONTENT_PROCESS_REUSE_PREF
|
||||
);
|
||||
try {
|
||||
// If we're asked to force a new process, replace the normal process
|
||||
// selector with one that always asks for a new process.
|
||||
// If DEFAULT_PROCESSSELECTOR_CID is null, we're in non-e10s mode and we
|
||||
// should skip this.
|
||||
if (options.forceNewProcess) {
|
||||
if (options.forceNewProcess && DEFAULT_PROCESSSELECTOR_CID) {
|
||||
Services.ppmm.releaseCachedProcesses();
|
||||
Services.prefs.setBoolPref(DISABLE_CONTENT_PROCESS_REUSE_PREF, true);
|
||||
registrar.registerFactory(
|
||||
OUR_PROCESSSELECTOR_CID,
|
||||
"",
|
||||
PROCESSSELECTOR_CONTRACTID,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
promises = [
|
||||
@ -235,10 +263,12 @@ var BrowserTestUtils = {
|
||||
}
|
||||
} finally {
|
||||
// Restore the original process selector, if needed.
|
||||
if (options.forceNewProcess) {
|
||||
Services.prefs.setBoolPref(
|
||||
DISABLE_CONTENT_PROCESS_REUSE_PREF,
|
||||
disableReusePrefValue
|
||||
if (options.forceNewProcess && DEFAULT_PROCESSSELECTOR_CID) {
|
||||
registrar.registerFactory(
|
||||
DEFAULT_PROCESSSELECTOR_CID,
|
||||
"",
|
||||
PROCESSSELECTOR_CONTRACTID,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user