Bug 1529022 - Add a GeckoChildProcessHosts iterator r=jld

Adds GeckoChildProcessHost::GetAll() and use it in ChromeUtils::GetProcInfo()

Differential Revision: https://phabricator.services.mozilla.com/D33920

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tarek Ziadé 2019-06-18 16:36:52 +00:00
parent b8c27feb30
commit 9f31044be3
9 changed files with 158 additions and 87 deletions

View File

@ -30,6 +30,7 @@
#include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/UnionTypes.h"
#include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options #include "mozilla/dom/WindowBinding.h" // For IdleRequestCallback/Options
#include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h" #include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/net/SocketProcessHost.h" #include "mozilla/net/SocketProcessHost.h"
#include "IOActivityMonitor.h" #include "IOActivityMonitor.h"
@ -692,67 +693,93 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
->Then( ->Then(
target, __func__, target, __func__,
[target, domPromise, parentPid](ProcInfo aParentInfo) { [target, domPromise, parentPid](ProcInfo aParentInfo) {
// Iterate over each child process to build an array of promises. // Get a list of ContentParent
nsTArray<ContentParent*> parents; nsTArray<ContentParent*> contentParents;
ContentParent::GetAll(parents); ContentParent::GetAll(contentParents);
nsTArray<RefPtr<ProcInfoPromise>> promises; nsTArray<RefPtr<ProcInfoPromise>> promises;
for (ContentParent* contentParent : parents) { mozilla::ipc::GeckoChildProcessHost::GetAll(
// Getting the child process id. [&promises, contentParents](
int32_t childPid = contentParent->Pid(); mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
if (childPid == -1) { if (!aGeckoProcess->GetChildProcessHandle()) {
continue; return;
} }
// Converting the Content Type into a ProcType
nsAutoString processType;
processType.Assign(contentParent->GetRemoteType());
mozilla::ProcType type = mozilla::ProcType::Unknown;
if (processType.EqualsLiteral(DEFAULT_REMOTE_TYPE)) {
type = mozilla::ProcType::Web;
} else if (processType.EqualsLiteral(FILE_REMOTE_TYPE)) {
type = mozilla::ProcType::File;
} else if (processType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
type = mozilla::ProcType::Extension;
} else if (processType.EqualsLiteral(
PRIVILEGEDABOUT_REMOTE_TYPE)) {
type = mozilla::ProcType::PrivilegedAbout;
} else if (processType.EqualsLiteral(
LARGE_ALLOCATION_REMOTE_TYPE)) {
type = mozilla::ProcType::WebLargeAllocation;
}
promises.AppendElement(mozilla::GetProcInfo( base::ProcessId childPid =
(base::ProcessId)childPid, contentParent->ChildID(), type, base::GetProcId(aGeckoProcess->GetChildProcessHandle());
contentParent->Process())); int32_t childId = 0;
} mozilla::ProcType type;
switch (aGeckoProcess->GetProcessType()) {
case GeckoProcessType::GeckoProcessType_Content: {
ContentParent* contentParent = nullptr;
// This loop can become slow as we get more processes in
// Fission, so might need some refactoring in the future.
for (ContentParent* parent : contentParents) {
// find the match
if (parent->Process() == aGeckoProcess) {
contentParent = parent;
break;
}
}
if (!contentParent) {
return;
}
// Converting the Content Type into a ProcType
nsAutoString processType;
processType.Assign(contentParent->GetRemoteType());
if (processType.EqualsLiteral(DEFAULT_REMOTE_TYPE)) {
type = mozilla::ProcType::Web;
} else if (processType.EqualsLiteral(FILE_REMOTE_TYPE)) {
type = mozilla::ProcType::File;
} else if (processType.EqualsLiteral(
EXTENSION_REMOTE_TYPE)) {
type = mozilla::ProcType::Extension;
} else if (processType.EqualsLiteral(
PRIVILEGEDABOUT_REMOTE_TYPE)) {
type = mozilla::ProcType::PrivilegedAbout;
} else if (processType.EqualsLiteral(
LARGE_ALLOCATION_REMOTE_TYPE)) {
type = mozilla::ProcType::WebLargeAllocation;
}
childId = contentParent->ChildID();
break;
}
case GeckoProcessType::GeckoProcessType_Default:
type = mozilla::ProcType::Browser;
break;
case GeckoProcessType::GeckoProcessType_Plugin:
type = mozilla::ProcType::Plugin;
break;
case GeckoProcessType::GeckoProcessType_GMPlugin:
type = mozilla::ProcType::GMPlugin;
break;
case GeckoProcessType::GeckoProcessType_GPU:
type = mozilla::ProcType::GPU;
break;
case GeckoProcessType::GeckoProcessType_VR:
type = mozilla::ProcType::VR;
break;
case GeckoProcessType::GeckoProcessType_RDD:
type = mozilla::ProcType::RDD;
break;
case GeckoProcessType::GeckoProcessType_Socket:
type = mozilla::ProcType::Socket;
break;
case GeckoProcessType::GeckoProcessType_RemoteSandboxBroker:
type = mozilla::ProcType::RemoteSandboxBroker;
break;
default:
type = mozilla::ProcType::Unknown;
}
// Getting the Socket Process promises.AppendElement(
int32_t SocketPid = net::gIOService->SocketProcessPid(); #ifdef XP_MACOSX
if (SocketPid != 0) { mozilla::GetProcInfo(childPid, childId, type,
promises.AppendElement(mozilla::GetProcInfo( aGeckoProcess->GetChildTask())
(base::ProcessId)SocketPid, 0, mozilla::ProcType::Socket, #else
net::gIOService->SocketProcess())); mozilla::GetProcInfo(childPid, childId, type)
} #endif
);
// Getting the GPU and RDD processes on supported platforms });
gfx::GPUProcessManager* pm = gfx::GPUProcessManager::Get();
if (pm) {
base::ProcessId GpuPid = pm->GPUProcessPid();
if (GpuPid != -1) {
promises.AppendElement(mozilla::GetProcInfo(
GpuPid, 0, mozilla::ProcType::Gpu, pm->Process()));
}
}
RDDProcessManager* RDDPm = RDDProcessManager::Get();
if (RDDPm) {
base::ProcessId RDDPid = RDDPm->RDDProcessPid();
if (RDDPid != -1) {
promises.AppendElement(mozilla::GetProcInfo(
RDDPid, 0, mozilla::ProcType::Rdd, RDDPm->Process()));
}
}
// two more processes to add: VR and GMP
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1529022
auto ProcInfoResolver = auto ProcInfoResolver =
[domPromise, parentPid, parentInfo = aParentInfo]( [domPromise, parentPid, parentInfo = aParentInfo](

View File

@ -37,6 +37,7 @@
#include "mozilla/ipc/BrowserProcessSubThread.h" #include "mozilla/ipc/BrowserProcessSubThread.h"
#include "mozilla/ipc/EnvironmentMap.h" #include "mozilla/ipc/EnvironmentMap.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Omnijar.h" #include "mozilla/Omnijar.h"
#include "mozilla/RecordReplay.h" #include "mozilla/RecordReplay.h"
#include "mozilla/RDDProcessHost.h" #include "mozilla/RDDProcessHost.h"
@ -102,6 +103,11 @@ static bool ShouldHaveDirectoryService() {
return GeckoProcessType_Default == XRE_GetProcessType(); return GeckoProcessType_Default == XRE_GetProcessType();
} }
StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
GeckoChildProcessHost::sGeckoChildProcessHosts;
StaticMutex GeckoChildProcessHost::sMutex;
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
bool aIsFileContent) bool aIsFileContent)
: mProcessType(aProcessType), : mProcessType(aProcessType),
@ -122,6 +128,11 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
#endif #endif
mDestroying(false) { mDestroying(false) {
MOZ_COUNT_CTOR(GeckoChildProcessHost); MOZ_COUNT_CTOR(GeckoChildProcessHost);
StaticMutexAutoLock lock(sMutex);
if (!sGeckoChildProcessHosts) {
sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
}
sGeckoChildProcessHosts->insertBack(this);
} }
GeckoChildProcessHost::~GeckoChildProcessHost() GeckoChildProcessHost::~GeckoChildProcessHost()
@ -168,8 +179,19 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
#endif #endif
} }
void GeckoChildProcessHost::RemoveFromProcessList() {
StaticMutexAutoLock lock(sMutex);
if (!sGeckoChildProcessHosts) {
return;
}
LinkedListElement<GeckoChildProcessHost>::removeFrom(
*sGeckoChildProcessHosts);
}
void GeckoChildProcessHost::Destroy() { void GeckoChildProcessHost::Destroy() {
MOZ_RELEASE_ASSERT(!mDestroying); MOZ_RELEASE_ASSERT(!mDestroying);
// We can remove from the list before it's really destroyed
RemoveFromProcessList();
RefPtr<HandlePromise> whenReady = mHandlePromise; RefPtr<HandlePromise> whenReady = mHandlePromise;
if (!whenReady) { if (!whenReady) {
@ -1459,3 +1481,13 @@ bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
} }
#endif /* XP_MACOSX && MOZ_SANDBOX */ #endif /* XP_MACOSX && MOZ_SANDBOX */
/* static */
void GeckoChildProcessHost::GetAll(const GeckoProcessCallback& aCallback) {
StaticMutexAutoLock lock(sMutex);
for (GeckoChildProcessHost* gp = sGeckoChildProcessHosts->getFirst(); gp;
gp = static_cast<mozilla::LinkedListElement<GeckoChildProcessHost>*>(gp)
->getNext()) {
aCallback(gp);
}
}

View File

@ -14,6 +14,7 @@
#include "mozilla/ipc/FileDescriptor.h" #include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Monitor.h" #include "mozilla/Monitor.h"
#include "mozilla/MozPromise.h" #include "mozilla/MozPromise.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
@ -37,7 +38,8 @@ typedef _MacSandboxInfo MacSandboxInfo;
namespace mozilla { namespace mozilla {
namespace ipc { namespace ipc {
class GeckoChildProcessHost : public ChildProcessHost { class GeckoChildProcessHost : public ChildProcessHost,
public LinkedListElement<GeckoChildProcessHost> {
protected: protected:
typedef mozilla::Monitor Monitor; typedef mozilla::Monitor Monitor;
typedef std::vector<std::string> StringVector; typedef std::vector<std::string> StringVector;
@ -153,10 +155,15 @@ class GeckoChildProcessHost : public ChildProcessHost {
return MacSandboxType_Utility; return MacSandboxType_Utility;
}; };
#endif #endif
typedef std::function<void(GeckoChildProcessHost*)> GeckoProcessCallback;
// Iterates over all instances and calls aCallback with each one of them.
// This method will lock any addition/removal of new processes
// so you need to make sure the callback is as fast as possible.
static void GetAll(const GeckoProcessCallback& aCallback);
protected: protected:
~GeckoChildProcessHost(); ~GeckoChildProcessHost();
GeckoProcessType mProcessType; GeckoProcessType mProcessType;
bool mIsFileContent; bool mIsFileContent;
Monitor mMonitor; Monitor mMonitor;
@ -241,6 +248,9 @@ class GeckoChildProcessHost : public ChildProcessHost {
// with launching the sub-process. // with launching the sub-process.
void GetChildLogName(const char* origLogName, nsACString& buffer); void GetChildLogName(const char* origLogName, nsACString& buffer);
// Removes the instance from sGeckoChildProcessHosts
void RemoveFromProcessList();
// In between launching the subprocess and handing off its IPC // In between launching the subprocess and handing off its IPC
// channel, there's a small window of time in which *we* might still // channel, there's a small window of time in which *we* might still
// be the channel listener, and receive messages. That's bad // be the channel listener, and receive messages. That's bad
@ -258,7 +268,9 @@ class GeckoChildProcessHost : public ChildProcessHost {
mozilla::Atomic<bool> mDestroying; mozilla::Atomic<bool> mDestroying;
static uint32_t sNextUniqueID; static uint32_t sNextUniqueID;
static StaticAutoPtr<LinkedList<GeckoChildProcessHost>>
sGeckoChildProcessHosts;
static StaticMutex sMutex;
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
void LaunchAndroidService( void LaunchAndroidService(
const char* type, const std::vector<std::string>& argv, const char* type, const std::vector<std::string>& argv,

View File

@ -24,14 +24,16 @@ enum class ProcType {
Extension, Extension,
PrivilegedAbout, PrivilegedAbout,
WebLargeAllocation, WebLargeAllocation,
// GPU process (only on Windows) // the rest matches GeckoProcessTypes.h
Gpu, Browser, // Default is named Browser here
// RDD process (Windows and macOS) Plugin,
Rdd, IPDLUnitTest,
// Socket process GMPlugin,
GPU,
VR,
RDD,
Socket, Socket,
// Main process RemoteSandboxBroker,
Browser,
// Unknown type of process // Unknown type of process
Unknown Unknown
}; };
@ -76,9 +78,14 @@ typedef MozPromise<ProcInfo, nsresult, true> ProcInfoPromise;
* Depending on the platform, this call can be quite expensive and the * Depending on the platform, this call can be quite expensive and the
* promise may return after several ms. * promise may return after several ms.
*/ */
RefPtr<ProcInfoPromise> GetProcInfo( #ifdef XP_MACOSX
base::ProcessId pid, int32_t childId, const ProcType& type, RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
ipc::GeckoChildProcessHost* childProcess = nullptr); const ProcType& type,
mach_port_t aChildTask = MACH_PORT_NULL);
#else
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& type);
#endif
} // namespace mozilla } // namespace mozilla
#endif // ProcInfo_h #endif // ProcInfo_h

View File

@ -10,8 +10,7 @@
namespace mozilla { namespace mozilla {
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& type, const ProcType& type) {
ipc::GeckoChildProcessHost* childProcess) {
// Not implemented on Android. // Not implemented on Android.
return nullptr; return nullptr;
} }

View File

@ -20,7 +20,7 @@
namespace mozilla { namespace mozilla {
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const ProcType& type, RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const ProcType& type,
ipc::GeckoChildProcessHost* childProcess) { mach_port_t aChildTask) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>(); auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__); RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
@ -32,12 +32,7 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const
return promise; return promise;
} }
mach_port_t task = MACH_PORT_NULL; auto ResolveGetProcinfo = [holder = std::move(holder), pid, type, childId, aChildTask]() {
if (childProcess && childProcess->GetChildTask() != MACH_PORT_NULL) {
task = childProcess->GetChildTask();
}
auto ResolveGetProcinfo = [holder = std::move(holder), pid, type, childId, task]() {
ProcInfo info; ProcInfo info;
info.pid = pid; info.pid = pid;
info.childId = childId; info.childId = childId;
@ -66,10 +61,10 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const
// Now getting threads info // Now getting threads info
mach_port_t selectedTask; mach_port_t selectedTask;
// If we did not get a task from a child process, we use mach_task_self() // If we did not get a task from a child process, we use mach_task_self()
if (task == MACH_PORT_NULL) { if (aChildTask == MACH_PORT_NULL) {
selectedTask = mach_task_self(); selectedTask = mach_task_self();
} else { } else {
selectedTask = task; selectedTask = aChildTask;
} }
// task_threads() gives us a snapshot of the process threads // task_threads() gives us a snapshot of the process threads
// but those threads can go away. All the code below makes // but those threads can go away. All the code below makes

View File

@ -208,8 +208,7 @@ class ThreadInfoReader final : public StatReader {
}; };
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& type, const ProcType& type) {
ipc::GeckoChildProcessHost* childProcess) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>(); auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__); RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
nsresult rv = NS_OK; nsresult rv = NS_OK;

View File

@ -73,8 +73,7 @@ void AppendThreads(ProcInfo* info) {
} }
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId,
const ProcType& type, const ProcType& type) {
ipc::GeckoChildProcessHost* childProcess) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>(); auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__); RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);

View File

@ -20,7 +20,8 @@
// said values are exposed to things like telemetry as well, so please // said values are exposed to things like telemetry as well, so please
// do not reorder lines in this file. // do not reorder lines in this file.
// //
// Please add new process types at the end of this list. // Please add new process types at the end of this list
// and update widget/ProcInfo.h
GECKO_PROCESS_TYPE(Default, "default", Parent, Self) GECKO_PROCESS_TYPE(Default, "default", Parent, Self)
GECKO_PROCESS_TYPE(Plugin, "plugin", Plugin, PluginContainer) GECKO_PROCESS_TYPE(Plugin, "plugin", Plugin, PluginContainer)
GECKO_PROCESS_TYPE(Content, "tab", Content, Self) GECKO_PROCESS_TYPE(Content, "tab", Content, Self)