Bug 1737828 - Avoid the main thread when starting PBackground, r=asuth,ipc-reviewers,necko-reviewers,kershaw,handyman

This patch avoids requiring the main thread to create PBackground instances by
instead using a background starter TaskQueue, and sending messages from a
PBackgroundStarter actor hosted on that thread to the target background thread
directly. On the background thread, the relevant metadata is already registered
and present in the BackgroundStarterParent actor allowing the main thread in
both processes to be bypassed completely.

Various tasks remain bound to the main thread, such as PBackground cleanup and
async steps involved in PBackground creation.

This patch also unifies the in-process and cross-process PBackground codepaths,
allowing in-process PBackground creation to bypass the main thread as well, and
removing the need for a main thread event target from
GetOrCreateForCurrentThread().

Differential Revision: https://phabricator.services.mozilla.com/D129705
This commit is contained in:
Nika Layzell 2022-01-10 20:09:14 +00:00
Родитель 7c01b8d9c1
Коммит f2916bb759
21 изменённых файлов: 473 добавлений и 725 удалений

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

@ -3738,8 +3738,8 @@ ContentParent::GetInterface(const nsIID& aIID, void** aResult) {
}
mozilla::ipc::IPCResult ContentParent::RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint) {
if (!BackgroundParent::Alloc(this, std::move(aEndpoint))) {
Endpoint<PBackgroundStarterParent>&& aEndpoint) {
if (!BackgroundParent::AllocStarter(this, std::move(aEndpoint))) {
NS_WARNING("BackgroundParent::Alloc failed");
}

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

@ -917,7 +917,7 @@ class ContentParent final
const nsACString& aContentProcessType);
mozilla::ipc::IPCResult RecvInitBackground(
Endpoint<mozilla::ipc::PBackgroundParent>&& aEndpoint);
Endpoint<mozilla::ipc::PBackgroundStarterParent>&& aEndpoint);
mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport);
mozilla::ipc::IPCResult RecvAddPerformanceMetrics(

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

@ -171,6 +171,7 @@ bool ContentProcess::Init(int aArgc, char* aArgv[]) {
// Do this as early as possible to get the parent process to initialize the
// background thread since we'll likely need database information very soon.
mozilla::ipc::BackgroundChild::Startup();
mozilla::ipc::BackgroundChild::InitContentStarter(&mContent);
return true;
}

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

@ -4,7 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include protocol PBackgroundStarter;
include protocol PBrowser;
include protocol PCompositorManager;
include protocol PContentPermissionRequest;
@ -1021,7 +1021,7 @@ parent:
async RemoveFromBFCache(MaybeDiscardedBrowsingContext aContext);
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
async InitBackground(Endpoint<PBackgroundStarterParent> aEndpoint);
async CreateGMPService();

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

@ -517,8 +517,7 @@ LSRequestChild* LSObject::StartRequest(nsIEventTarget* aMainEventTarget,
mozilla::ipc::PBackgroundChild* backgroundActor =
XRE_IsParentProcess()
? mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(
aMainEventTarget)
? mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread()
: mozilla::ipc::BackgroundChild::GetForCurrentThread();
if (NS_WARN_IF(!backgroundActor)) {
return nullptr;

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

@ -16,6 +16,7 @@ namespace mozilla {
namespace dom {
class BlobImpl;
class ContentChild;
class ContentParent;
class ContentProcess;
@ -24,12 +25,14 @@ class ContentProcess;
namespace net {
class SocketProcessChild;
class SocketProcessBridgeChild;
} // namespace net
namespace ipc {
class PBackgroundChild;
class PBackgroundStarterChild;
// This class allows access to the PBackground protocol. PBackground allows
// communication between any thread (in the parent or a child process) and a
@ -53,6 +56,10 @@ class PBackgroundChild;
//
// The PBackgroundChild actor and all its sub-protocol actors will be
// automatically destroyed when its designated thread completes.
//
// Init{Content,Socket,SocketBridge}Starter must be called on the main thread
// with an actor bridging to the relevant target process type before these
// methods can be used.
class BackgroundChild final {
friend class mozilla::dom::ContentParent;
friend class mozilla::dom::ContentProcess;
@ -65,19 +72,26 @@ class BackgroundChild final {
static PBackgroundChild* GetForCurrentThread();
// See above.
static PBackgroundChild* GetOrCreateForCurrentThread(
nsIEventTarget* aMainEventTarget = nullptr);
static PBackgroundChild* GetOrCreateForCurrentThread();
// See above.
static PBackgroundChild* GetOrCreateSocketActorForCurrentThread();
// See above.
static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread();
// See above.
static void CloseForCurrentThread();
// See above.
static PBackgroundChild* GetOrCreateSocketActorForCurrentThread(
nsIEventTarget* aMainEventTarget = nullptr);
static void InitContentStarter(mozilla::dom::ContentChild* aContent);
// See above.
static PBackgroundChild* GetOrCreateForSocketParentBridgeForCurrentThread(
nsIEventTarget* aMainEventTarget = nullptr);
static void InitSocketStarter(mozilla::net::SocketProcessChild* aSocket);
// See above.
static void InitSocketBridgeStarter(
mozilla::net::SocketProcessBridgeChild* aSocketBridge);
private:
// Only called by this class's friends.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -37,7 +37,9 @@ class ContentParent;
namespace ipc {
class BackgroundStarterParent;
class PBackgroundParent;
class PBackgroundStarterParent;
template <class PFooSide>
class Endpoint;
@ -45,14 +47,15 @@ class Endpoint;
// This class is not designed for public consumption beyond the few static
// member functions.
class BackgroundParent final {
friend class mozilla::ipc::BackgroundStarterParent;
friend class mozilla::dom::ContentParent;
friend class mozilla::net::SocketProcessBridgeParent;
friend class mozilla::net::SocketProcessParent;
typedef base::ProcessId ProcessId;
typedef mozilla::dom::BlobImpl BlobImpl;
typedef mozilla::dom::ContentParent ContentParent;
typedef mozilla::ipc::Transport Transport;
friend class mozilla::net::SocketProcessBridgeParent;
friend class mozilla::net::SocketProcessParent;
public:
// This function allows the caller to determine if the given parent actor
@ -81,17 +84,14 @@ class BackgroundParent final {
static uint64_t GetChildID(PBackgroundParent* aBackgroundActor);
static bool GetLiveActorArray(PBackgroundParent* aBackgroundActor,
nsTArray<PBackgroundParent*>& aLiveActorArray);
private:
// Only called by ContentParent for cross-process actors.
static bool Alloc(ContentParent* aContent,
Endpoint<PBackgroundParent>&& aEndpoint);
static bool AllocStarter(ContentParent* aContent,
Endpoint<PBackgroundStarterParent>&& aEndpoint);
// Called by SocketProcessBridgeParent and SocketProcessParent for
// cross-process actors.
static bool Alloc(Endpoint<PBackgroundParent>&& aEndpoint);
static bool AllocStarter(Endpoint<PBackgroundStarterParent>&& aEndpoint);
};
// Implemented in BackgroundImpl.cpp.

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

@ -125,7 +125,6 @@ using mozilla::dom::ContentParent;
BackgroundParentImpl::BackgroundParentImpl() {
AssertIsInMainOrSocketProcess();
AssertIsOnMainThread();
MOZ_COUNT_CTOR(mozilla::ipc::BackgroundParentImpl);
}

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

@ -0,0 +1,26 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_BackgroundStarterChild_h
#define mozilla_ipc_BackgroundStarterChild_h
#include "mozilla/ipc/PBackgroundStarterChild.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla::ipc {
class BackgroundStarterChild final : public PBackgroundStarterChild {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BackgroundStarterChild, override)
private:
friend class PBackgroundStarterChild;
~BackgroundStarterChild() = default;
};
} // namespace mozilla::ipc
#endif // mozilla_ipc_BackgroundStarterChild_h

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

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ipc_BackgroundStarterParent_h
#define mozilla_ipc_BackgroundStarterParent_h
#include "mozilla/ipc/PBackgroundStarterParent.h"
#include "mozilla/dom/ContentParent.h"
#include "nsISupportsImpl.h"
namespace mozilla::ipc {
class BackgroundStarterParent final : public PBackgroundStarterParent {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(
BackgroundStarterParent, override)
// Implemented in BackgroundImpl.cpp
BackgroundStarterParent(mozilla::dom::ContentParent* aContent,
bool aCrossProcess);
void SetLiveActorArray(nsTArray<IToplevelProtocol*>* aLiveActorArray);
private:
friend class PBackgroundStarterParent;
~BackgroundStarterParent() = default;
// Implemented in BackgroundImpl.cpp
void ActorDestroy(ActorDestroyReason aReason) override;
// Implemented in BackgroundImpl.cpp
IPCResult RecvInitBackground(Endpoint<PBackgroundParent>&& aEndpoint);
const bool mCrossProcess;
RefPtr<mozilla::dom::ContentParent> mContent;
// Set when the actor is opened successfully and used to handle shutdown
// hangs. Only touched on the background thread.
nsTArray<IToplevelProtocol*>* mLiveActorArray = nullptr;
};
} // namespace mozilla::ipc
#endif // mozilla_ipc_BackgroundStarterParent_h

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

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
namespace mozilla {
namespace ipc {
[RefCounted, NeedsOtherPid]
async protocol PBackgroundStarter
{
parent:
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
};
} // namespace ipc
} // namespace mozilla

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

@ -13,6 +13,8 @@ EXPORTS.mozilla.ipc += [
"AutoTransportDescriptor.h",
"BackgroundChild.h",
"BackgroundParent.h",
"BackgroundStarterChild.h",
"BackgroundStarterParent.h",
"BackgroundUtils.h",
"BrowserProcessSubThread.h",
"ByteBuf.h",
@ -226,6 +228,7 @@ IPDL_SOURCES = [
"IPCStream.ipdlh",
"PBackground.ipdl",
"PBackgroundSharedTypes.ipdlh",
"PBackgroundStarter.ipdl",
"PBackgroundTest.ipdl",
"PChildToParentStream.ipdl",
"PFileDescriptorSet.ipdl",

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

@ -13,7 +13,7 @@ include protocol PFileDescriptorSet;
include protocol PChildToParentStream;
include protocol PParentToChildStream;
include protocol PInputChannelThrottleQueue;
include protocol PBackground;
include protocol PBackgroundStarter;
include protocol PAltService;
include protocol PAltSvcTransaction;
include protocol PTRRService;
@ -126,7 +126,7 @@ parent:
PRTime aTimestamp,
uint64_t aExtraSizeData,
nsCString aExtraStringData);
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
async InitBackground(Endpoint<PBackgroundStarterParent> aEndpoint);
async PAltService();
sync GetTLSClientCert(nsCString aHostName,
OriginAttributes aOriginAttributes,

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

@ -4,7 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include protocol PBackgroundStarter;
namespace mozilla {
namespace net {
@ -22,7 +22,7 @@ sync protocol PSocketProcessBridge
{
parent:
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
async InitBackground(Endpoint<PBackgroundStarterParent> aEndpoint);
both:
async Test();
};

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

@ -33,6 +33,8 @@ bool SocketProcessBridgeChild::Create(
sSocketProcessBridgeChild =
new SocketProcessBridgeChild(std::move(aEndpoint));
if (sSocketProcessBridgeChild->Inited()) {
mozilla::ipc::BackgroundChild::InitSocketBridgeStarter(
sSocketProcessBridgeChild);
return true;
}

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

@ -37,9 +37,9 @@ mozilla::ipc::IPCResult SocketProcessBridgeParent::RecvTest() {
}
mozilla::ipc::IPCResult SocketProcessBridgeParent::RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint) {
Endpoint<PBackgroundStarterParent>&& aEndpoint) {
LOG(("SocketProcessBridgeParent::RecvInitBackground mId=%d\n", mId));
if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) {
if (!ipc::BackgroundParent::AllocStarter(nullptr, std::move(aEndpoint))) {
return IPC_FAIL(this, "BackgroundParent::Alloc failed");
}

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

@ -24,7 +24,7 @@ class SocketProcessBridgeParent final : public PSocketProcessBridgeParent {
mozilla::ipc::IPCResult RecvTest();
mozilla::ipc::IPCResult RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint);
Endpoint<PBackgroundStarterParent>&& aEndpoint);
void ActorDestroy(ActorDestroyReason aWhy) override;
void DeferredDestroy();

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

@ -147,6 +147,8 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid,
}
BackgroundChild::Startup();
BackgroundChild::InitSocketStarter(this);
SetThisProcessName("Socket Process");
#if defined(XP_MACOSX)
// Close all current connections to the WindowServer. This ensures that the

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

@ -296,9 +296,9 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvObserveHttpActivity(
}
mozilla::ipc::IPCResult SocketProcessParent::RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint) {
Endpoint<PBackgroundStarterParent>&& aEndpoint) {
LOG(("SocketProcessParent::RecvInitBackground\n"));
if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) {
if (!ipc::BackgroundParent::AllocStarter(nullptr, std::move(aEndpoint))) {
return IPC_FAIL(this, "BackgroundParent::Alloc failed");
}

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

@ -90,7 +90,7 @@ class SocketProcessParent final
const uint64_t& aExtraSizeData, const nsCString& aExtraStringData);
mozilla::ipc::IPCResult RecvInitBackground(
Endpoint<PBackgroundParent>&& aEndpoint);
Endpoint<PBackgroundStarterParent>&& aEndpoint);
already_AddRefed<PAltServiceParent> AllocPAltServiceParent();