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/WindowBinding.h" // For IdleRequestCallback/Options
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/net/UrlClassifierFeatureFactory.h"
#include "mozilla/net/SocketProcessHost.h"
#include "IOActivityMonitor.h"
@ -692,67 +693,93 @@ already_AddRefed<Promise> ChromeUtils::RequestProcInfo(GlobalObject& aGlobal,
->Then(
target, __func__,
[target, domPromise, parentPid](ProcInfo aParentInfo) {
// Iterate over each child process to build an array of promises.
nsTArray<ContentParent*> parents;
ContentParent::GetAll(parents);
// Get a list of ContentParent
nsTArray<ContentParent*> contentParents;
ContentParent::GetAll(contentParents);
nsTArray<RefPtr<ProcInfoPromise>> promises;
for (ContentParent* contentParent : parents) {
// Getting the child process id.
int32_t childPid = contentParent->Pid();
if (childPid == -1) {
continue;
}
// 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;
}
mozilla::ipc::GeckoChildProcessHost::GetAll(
[&promises, contentParents](
mozilla::ipc::GeckoChildProcessHost* aGeckoProcess) {
if (!aGeckoProcess->GetChildProcessHandle()) {
return;
}
promises.AppendElement(mozilla::GetProcInfo(
(base::ProcessId)childPid, contentParent->ChildID(), type,
contentParent->Process()));
}
base::ProcessId childPid =
base::GetProcId(aGeckoProcess->GetChildProcessHandle());
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
int32_t SocketPid = net::gIOService->SocketProcessPid();
if (SocketPid != 0) {
promises.AppendElement(mozilla::GetProcInfo(
(base::ProcessId)SocketPid, 0, mozilla::ProcType::Socket,
net::gIOService->SocketProcess()));
}
// 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
promises.AppendElement(
#ifdef XP_MACOSX
mozilla::GetProcInfo(childPid, childId, type,
aGeckoProcess->GetChildTask())
#else
mozilla::GetProcInfo(childPid, childId, type)
#endif
);
});
auto ProcInfoResolver =
[domPromise, parentPid, parentInfo = aParentInfo](

View File

@ -37,6 +37,7 @@
#include "mozilla/ipc/BrowserProcessSubThread.h"
#include "mozilla/ipc/EnvironmentMap.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Omnijar.h"
#include "mozilla/RecordReplay.h"
#include "mozilla/RDDProcessHost.h"
@ -102,6 +103,11 @@ static bool ShouldHaveDirectoryService() {
return GeckoProcessType_Default == XRE_GetProcessType();
}
StaticAutoPtr<mozilla::LinkedList<GeckoChildProcessHost>>
GeckoChildProcessHost::sGeckoChildProcessHosts;
StaticMutex GeckoChildProcessHost::sMutex;
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
bool aIsFileContent)
: mProcessType(aProcessType),
@ -122,6 +128,11 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
#endif
mDestroying(false) {
MOZ_COUNT_CTOR(GeckoChildProcessHost);
StaticMutexAutoLock lock(sMutex);
if (!sGeckoChildProcessHosts) {
sGeckoChildProcessHosts = new mozilla::LinkedList<GeckoChildProcessHost>();
}
sGeckoChildProcessHosts->insertBack(this);
}
GeckoChildProcessHost::~GeckoChildProcessHost()
@ -168,8 +179,19 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
#endif
}
void GeckoChildProcessHost::RemoveFromProcessList() {
StaticMutexAutoLock lock(sMutex);
if (!sGeckoChildProcessHosts) {
return;
}
LinkedListElement<GeckoChildProcessHost>::removeFrom(
*sGeckoChildProcessHosts);
}
void GeckoChildProcessHost::Destroy() {
MOZ_RELEASE_ASSERT(!mDestroying);
// We can remove from the list before it's really destroyed
RemoveFromProcessList();
RefPtr<HandlePromise> whenReady = mHandlePromise;
if (!whenReady) {
@ -1459,3 +1481,13 @@ bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
}
#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/Atomics.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Monitor.h"
#include "mozilla/MozPromise.h"
#include "mozilla/StaticPtr.h"
@ -37,7 +38,8 @@ typedef _MacSandboxInfo MacSandboxInfo;
namespace mozilla {
namespace ipc {
class GeckoChildProcessHost : public ChildProcessHost {
class GeckoChildProcessHost : public ChildProcessHost,
public LinkedListElement<GeckoChildProcessHost> {
protected:
typedef mozilla::Monitor Monitor;
typedef std::vector<std::string> StringVector;
@ -153,10 +155,15 @@ class GeckoChildProcessHost : public ChildProcessHost {
return MacSandboxType_Utility;
};
#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:
~GeckoChildProcessHost();
GeckoProcessType mProcessType;
bool mIsFileContent;
Monitor mMonitor;
@ -241,6 +248,9 @@ class GeckoChildProcessHost : public ChildProcessHost {
// with launching the sub-process.
void GetChildLogName(const char* origLogName, nsACString& buffer);
// Removes the instance from sGeckoChildProcessHosts
void RemoveFromProcessList();
// In between launching the subprocess and handing off its IPC
// channel, there's a small window of time in which *we* might still
// be the channel listener, and receive messages. That's bad
@ -258,7 +268,9 @@ class GeckoChildProcessHost : public ChildProcessHost {
mozilla::Atomic<bool> mDestroying;
static uint32_t sNextUniqueID;
static StaticAutoPtr<LinkedList<GeckoChildProcessHost>>
sGeckoChildProcessHosts;
static StaticMutex sMutex;
#if defined(MOZ_WIDGET_ANDROID)
void LaunchAndroidService(
const char* type, const std::vector<std::string>& argv,

View File

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

View File

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

View File

@ -20,7 +20,7 @@
namespace mozilla {
RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const ProcType& type,
ipc::GeckoChildProcessHost* childProcess) {
mach_port_t aChildTask) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
@ -32,12 +32,7 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const
return promise;
}
mach_port_t task = MACH_PORT_NULL;
if (childProcess && childProcess->GetChildTask() != MACH_PORT_NULL) {
task = childProcess->GetChildTask();
}
auto ResolveGetProcinfo = [holder = std::move(holder), pid, type, childId, task]() {
auto ResolveGetProcinfo = [holder = std::move(holder), pid, type, childId, aChildTask]() {
ProcInfo info;
info.pid = pid;
info.childId = childId;
@ -66,10 +61,10 @@ RefPtr<ProcInfoPromise> GetProcInfo(base::ProcessId pid, int32_t childId, const
// Now getting threads info
mach_port_t selectedTask;
// 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();
} else {
selectedTask = task;
selectedTask = aChildTask;
}
// task_threads() gives us a snapshot of the process threads
// 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,
const ProcType& type,
ipc::GeckoChildProcessHost* childProcess) {
const ProcType& type) {
auto holder = MakeUnique<MozPromiseHolder<ProcInfoPromise>>();
RefPtr<ProcInfoPromise> promise = holder->Ensure(__func__);
nsresult rv = NS_OK;

View File

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

View File

@ -20,7 +20,8 @@
// said values are exposed to things like telemetry as well, so please
// 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(Plugin, "plugin", Plugin, PluginContainer)
GECKO_PROCESS_TYPE(Content, "tab", Content, Self)