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:
Butkovits Atila 2021-09-27 18:54:29 +03:00
parent 2248ff6da9
commit 24d8b4f45f
15 changed files with 366 additions and 155 deletions

View File

@ -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__,

View 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"];

View File

@ -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'],

View File

@ -506,6 +506,7 @@ EXTRA_JS_MODULES += [
"DOMRequestHelper.jsm",
"IndexedDBHelper.jsm",
"LocationHelper.jsm",
"ProcessSelector.jsm",
"SlowScriptDebug.jsm",
]

View File

@ -15,6 +15,7 @@ XPIDL_SOURCES += [
"nsIBrowserUsage.idl",
"nsIContentPermissionPrompt.idl",
"nsIContentPrefService2.idl",
"nsIContentProcess.idl",
"nsIDOMChromeWindow.idl",
"nsIDOMGlobalPropertyInitializer.idl",
"nsIDOMWindow.idl",

View 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);
};

View File

@ -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()) {

View File

@ -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();

View File

@ -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) {

View File

@ -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;

View File

@ -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__,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
);
}
}