зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1753424 - Support running multiple UtilityProcess r=nika
Differential Revision: https://phabricator.services.mozilla.com/D139817
This commit is contained in:
Родитель
6c667ad60a
Коммит
baebfcdc76
|
@ -164,7 +164,8 @@ mozilla::ipc::IPCResult UtilityProcessChild::RecvRequestMemoryReport(
|
||||||
const uint32_t& aGeneration, const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile,
|
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile,
|
||||||
const RequestMemoryReportResolver& aResolver) {
|
const RequestMemoryReportResolver& aResolver) {
|
||||||
nsPrintfCString processName("Utility (pid %u)", base::GetCurrentProcId());
|
nsPrintfCString processName("Utility (pid: %u, sandboxingKind: %" PRIu64 ")",
|
||||||
|
base::GetCurrentProcId(), mSandbox);
|
||||||
|
|
||||||
mozilla::dom::MemoryReportRequestClient::Start(
|
mozilla::dom::MemoryReportRequestClient::Start(
|
||||||
aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
|
aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
|
||||||
|
|
|
@ -72,9 +72,9 @@ class UtilityProcessHost final : public mozilla::ipc::GeckoChildProcessHost {
|
||||||
|
|
||||||
// Return the actor for the top-level actor of the process. If the process
|
// Return the actor for the top-level actor of the process. If the process
|
||||||
// has not connected yet, this returns null.
|
// has not connected yet, this returns null.
|
||||||
UtilityProcessParent* GetActor() const {
|
RefPtr<UtilityProcessParent> GetActor() const {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
return mUtilityProcessParent.get();
|
return mUtilityProcessParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConnected() const {
|
bool IsConnected() const {
|
||||||
|
|
|
@ -44,7 +44,7 @@ bool UtilityProcessImpl::Init(int aArgc, char* aArgv[]) {
|
||||||
// This checks needs to be kept in sync with SandboxingKind enum living in
|
// This checks needs to be kept in sync with SandboxingKind enum living in
|
||||||
// ipc/glue/UtilityProcessSandboxing.h
|
// ipc/glue/UtilityProcessSandboxing.h
|
||||||
if (*sandboxingKind < SandboxingKind::GENERIC_UTILITY ||
|
if (*sandboxingKind < SandboxingKind::GENERIC_UTILITY ||
|
||||||
*sandboxingKind > SandboxingKind::GENERIC_UTILITY) {
|
*sandboxingKind >= SandboxingKind::COUNT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,8 @@ UtilityProcessManager::UtilityProcessManager() : mObserver(new Observer(this)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
UtilityProcessManager::~UtilityProcessManager() {
|
UtilityProcessManager::~UtilityProcessManager() {
|
||||||
// The Utility process should have already been shut down.
|
// The Utility process should ALL have already been shut down.
|
||||||
MOZ_ASSERT(!mProcess && !mProcessParent);
|
MOZ_ASSERT(NoMoreProcesses());
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(UtilityProcessManager::Observer, nsIObserver);
|
NS_IMPL_ISUPPORTS(UtilityProcessManager::Observer, nsIObserver);
|
||||||
|
@ -80,16 +80,15 @@ void UtilityProcessManager::OnXPCOMShutdown() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
sXPCOMShutdown = true;
|
sXPCOMShutdown = true;
|
||||||
nsContentUtils::UnregisterShutdownObserver(mObserver);
|
nsContentUtils::UnregisterShutdownObserver(mObserver);
|
||||||
CleanShutdown();
|
CleanShutdownAllProcesses();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityProcessManager::OnPreferenceChange(const char16_t* aData) {
|
void UtilityProcessManager::OnPreferenceChange(const char16_t* aData) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (!mProcess) {
|
if (NoMoreProcesses()) {
|
||||||
// Process hasn't been launched yet
|
// Process hasn't been launched yet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We know prefs are ASCII here.
|
// We know prefs are ASCII here.
|
||||||
NS_LossyConvertUTF16toASCII strData(aData);
|
NS_LossyConvertUTF16toASCII strData(aData);
|
||||||
|
|
||||||
|
@ -100,14 +99,29 @@ void UtilityProcessManager::OnPreferenceChange(const char16_t* aData) {
|
||||||
|
|
||||||
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
|
mozilla::dom::Pref pref(strData, /* isLocked */ false, Nothing(), Nothing());
|
||||||
Preferences::GetPreference(&pref);
|
Preferences::GetPreference(&pref);
|
||||||
if (bool(mProcessParent)) {
|
|
||||||
MOZ_ASSERT(mQueuedPrefs.IsEmpty());
|
for (auto& p : mProcesses) {
|
||||||
Unused << mProcessParent->SendPreferenceUpdate(pref);
|
if (!p) {
|
||||||
} else if (IsProcessLaunching()) {
|
continue;
|
||||||
mQueuedPrefs.AppendElement(pref);
|
}
|
||||||
|
|
||||||
|
if (p->mProcessParent) {
|
||||||
|
Unused << p->mProcessParent->SendPreferenceUpdate(pref);
|
||||||
|
} else if (IsProcessLaunching(p->mSandbox)) {
|
||||||
|
p->mQueuedPrefs.AppendElement(pref);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<UtilityProcessManager::ProcessFields> UtilityProcessManager::GetProcess(
|
||||||
|
SandboxingKind aSandbox) {
|
||||||
|
if (!mProcesses[aSandbox]) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mProcesses[aSandbox];
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<GenericNonExclusivePromise> UtilityProcessManager::LaunchProcess(
|
RefPtr<GenericNonExclusivePromise> UtilityProcessManager::LaunchProcess(
|
||||||
SandboxingKind aSandbox) {
|
SandboxingKind aSandbox) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -117,14 +131,20 @@ RefPtr<GenericNonExclusivePromise> UtilityProcessManager::LaunchProcess(
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNumProcessAttempts) {
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (p && p->mNumProcessAttempts) {
|
||||||
// We failed to start the Utility process earlier, abort now.
|
// We failed to start the Utility process earlier, abort now.
|
||||||
return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mLaunchPromise && mProcess) {
|
if (p && p->mLaunchPromise && p->mProcess) {
|
||||||
return mLaunchPromise;
|
return p->mLaunchPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
p = new ProcessFields(aSandbox);
|
||||||
|
mProcesses[aSandbox] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> extraArgs;
|
std::vector<std::string> extraArgs;
|
||||||
|
@ -133,38 +153,37 @@ RefPtr<GenericNonExclusivePromise> UtilityProcessManager::LaunchProcess(
|
||||||
|
|
||||||
// The subprocess is launched asynchronously, so we
|
// The subprocess is launched asynchronously, so we
|
||||||
// wait for the promise to be resolved to acquire the IPDL actor.
|
// wait for the promise to be resolved to acquire the IPDL actor.
|
||||||
mProcess = new UtilityProcessHost(aSandbox, this);
|
p->mProcess = new UtilityProcessHost(aSandbox, this);
|
||||||
if (!mProcess->Launch(extraArgs)) {
|
if (!p->mProcess->Launch(extraArgs)) {
|
||||||
mNumProcessAttempts++;
|
p->mNumProcessAttempts++;
|
||||||
DestroyProcess();
|
DestroyProcess(aSandbox);
|
||||||
return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE,
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<UtilityProcessManager> self = this;
|
RefPtr<UtilityProcessManager> self = this;
|
||||||
mLaunchPromise = mProcess->LaunchPromise()->Then(
|
p->mLaunchPromise = p->mProcess->LaunchPromise()->Then(
|
||||||
GetMainThreadSerialEventTarget(), __func__,
|
GetMainThreadSerialEventTarget(), __func__,
|
||||||
[self, aSandbox](bool) {
|
[self, p, aSandbox](bool) {
|
||||||
if (self->IsShutdown()) {
|
if (self->IsShutdown()) {
|
||||||
return GenericNonExclusivePromise::CreateAndReject(
|
return GenericNonExclusivePromise::CreateAndReject(
|
||||||
NS_ERROR_NOT_AVAILABLE, __func__);
|
NS_ERROR_NOT_AVAILABLE, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->IsProcessDestroyed()) {
|
if (self->IsProcessDestroyed(aSandbox)) {
|
||||||
return GenericNonExclusivePromise::CreateAndReject(
|
return GenericNonExclusivePromise::CreateAndReject(
|
||||||
NS_ERROR_NOT_AVAILABLE, __func__);
|
NS_ERROR_NOT_AVAILABLE, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->mProcessParent = self->mProcess->GetActor();
|
p->mProcessParent = p->mProcess->GetActor();
|
||||||
|
|
||||||
// Flush any pref updates that happened during
|
// Flush any pref updates that happened during
|
||||||
// launch and weren't included in the blobs set
|
// launch and weren't included in the blobs set
|
||||||
// up in LaunchUtilityProcess.
|
// up in LaunchUtilityProcess.
|
||||||
for (const mozilla::dom::Pref& pref : self->mQueuedPrefs) {
|
for (const mozilla::dom::Pref& pref : p->mQueuedPrefs) {
|
||||||
Unused << NS_WARN_IF(
|
Unused << NS_WARN_IF(!p->mProcessParent->SendPreferenceUpdate(pref));
|
||||||
!self->mProcessParent->SendPreferenceUpdate(pref));
|
|
||||||
}
|
}
|
||||||
self->mQueuedPrefs.Clear();
|
p->mQueuedPrefs.Clear();
|
||||||
|
|
||||||
CrashReporter::AnnotateCrashReport(
|
CrashReporter::AnnotateCrashReport(
|
||||||
CrashReporter::Annotation::UtilityProcessStatus, "Running"_ns);
|
CrashReporter::Annotation::UtilityProcessStatus, "Running"_ns);
|
||||||
|
@ -175,65 +194,123 @@ RefPtr<GenericNonExclusivePromise> UtilityProcessManager::LaunchProcess(
|
||||||
|
|
||||||
return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
|
return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
|
||||||
},
|
},
|
||||||
[self](nsresult aError) {
|
[self, p, aSandbox](nsresult aError) {
|
||||||
if (GetSingleton()) {
|
if (GetSingleton()) {
|
||||||
self->mNumProcessAttempts++;
|
p->mNumProcessAttempts++;
|
||||||
self->DestroyProcess();
|
self->DestroyProcess(aSandbox);
|
||||||
}
|
}
|
||||||
return GenericNonExclusivePromise::CreateAndReject(aError, __func__);
|
return GenericNonExclusivePromise::CreateAndReject(aError, __func__);
|
||||||
});
|
});
|
||||||
return mLaunchPromise;
|
|
||||||
|
return p->mLaunchPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UtilityProcessManager::IsProcessLaunching() {
|
bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
return mProcess && !mProcessParent;
|
|
||||||
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (!p) {
|
||||||
|
MOZ_CRASH("Cannot check process launching with no process");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p->mProcess && !(p->mProcessParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UtilityProcessManager::IsProcessDestroyed() const {
|
bool UtilityProcessManager::IsProcessDestroyed(SandboxingKind aSandbox) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
return !mProcessParent && !mProcess;
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (!p) {
|
||||||
|
MOZ_CRASH("Cannot check process destroyed with no process");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !p->mProcess && !p->mProcessParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UtilityProcessManager::OnProcessUnexpectedShutdown(
|
void UtilityProcessManager::OnProcessUnexpectedShutdown(
|
||||||
UtilityProcessHost* aHost) {
|
UtilityProcessHost* aHost) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mProcess && mProcess == aHost);
|
|
||||||
|
|
||||||
mNumUnexpectedCrashes++;
|
for (auto& it : mProcesses) {
|
||||||
|
if (it && it->mProcess && it->mProcess == aHost) {
|
||||||
DestroyProcess();
|
it->mNumUnexpectedCrashes++;
|
||||||
}
|
DestroyProcess(it->mSandbox);
|
||||||
|
return;
|
||||||
void UtilityProcessManager::CleanShutdown() { DestroyProcess(); }
|
}
|
||||||
|
|
||||||
void UtilityProcessManager::DestroyProcess() {
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mQueuedPrefs.Clear();
|
|
||||||
if (mObserver) {
|
|
||||||
Preferences::RemoveObserver(mObserver, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mObserver = nullptr;
|
MOZ_CRASH(
|
||||||
mProcessParent = nullptr;
|
"Called UtilityProcessManager::OnProcessUnexpectedShutdown with invalid "
|
||||||
sSingleton = nullptr;
|
"aHost");
|
||||||
|
}
|
||||||
|
|
||||||
if (!mProcess) {
|
void UtilityProcessManager::CleanShutdownAllProcesses() {
|
||||||
|
for (auto& it : mProcesses) {
|
||||||
|
if (it) {
|
||||||
|
DestroyProcess(it->mSandbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UtilityProcessManager::CleanShutdown(SandboxingKind aSandbox) {
|
||||||
|
DestroyProcess(aSandbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t UtilityProcessManager::AliveProcesses() {
|
||||||
|
uint16_t alive = 0;
|
||||||
|
for (auto& p : mProcesses) {
|
||||||
|
if (p != nullptr) {
|
||||||
|
alive++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UtilityProcessManager::NoMoreProcesses() { return AliveProcesses() == 0; }
|
||||||
|
|
||||||
|
void UtilityProcessManager::DestroyProcess(SandboxingKind aSandbox) {
|
||||||
|
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (AliveProcesses() <= 1) {
|
||||||
|
if (mObserver) {
|
||||||
|
Preferences::RemoveObserver(mObserver, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
mObserver = nullptr;
|
||||||
|
sSingleton = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (!p) {
|
||||||
|
MOZ_CRASH("Cannot get no ProcessFields");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mProcess->Shutdown();
|
p->mQueuedPrefs.Clear();
|
||||||
mProcess = nullptr;
|
p->mProcessParent = nullptr;
|
||||||
|
|
||||||
|
if (!p->mProcess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->mProcess->Shutdown();
|
||||||
|
p->mProcess = nullptr;
|
||||||
|
|
||||||
|
mProcesses[aSandbox] = nullptr;
|
||||||
|
|
||||||
CrashReporter::AnnotateCrashReport(
|
CrashReporter::AnnotateCrashReport(
|
||||||
CrashReporter::Annotation::UtilityProcessStatus, "Destroyed"_ns);
|
CrashReporter::Annotation::UtilityProcessStatus, "Destroyed"_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<base::ProcessId> UtilityProcessManager::ProcessPid() {
|
Maybe<base::ProcessId> UtilityProcessManager::ProcessPid(
|
||||||
|
SandboxingKind aSandbox) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (mProcessParent) {
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
return Some(mProcessParent->OtherPid());
|
if (!p) {
|
||||||
|
return Nothing();
|
||||||
|
}
|
||||||
|
if (p->mProcessParent) {
|
||||||
|
return Some(p->mProcessParent->OtherPid());
|
||||||
}
|
}
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
|
@ -242,13 +319,17 @@ class UtilityMemoryReporter : public MemoryReportingProcess {
|
||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityMemoryReporter, override)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UtilityMemoryReporter, override)
|
||||||
|
|
||||||
|
explicit UtilityMemoryReporter(UtilityProcessParent* aParent) {
|
||||||
|
mParent = aParent;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsAlive() const override { return bool(GetParent()); }
|
bool IsAlive() const override { return bool(GetParent()); }
|
||||||
|
|
||||||
bool SendRequestMemoryReport(
|
bool SendRequestMemoryReport(
|
||||||
const uint32_t& aGeneration, const bool& aAnonymize,
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
||||||
const bool& aMinimizeMemoryUsage,
|
const bool& aMinimizeMemoryUsage,
|
||||||
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
|
const Maybe<ipc::FileDescriptor>& aDMDFile) override {
|
||||||
UtilityProcessParent* parent = GetParent();
|
RefPtr<UtilityProcessParent> parent = GetParent();
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -258,33 +339,24 @@ class UtilityMemoryReporter : public MemoryReportingProcess {
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Pid() const override {
|
int32_t Pid() const override {
|
||||||
if (UtilityProcessParent* parent = GetParent()) {
|
if (RefPtr<UtilityProcessParent> parent = GetParent()) {
|
||||||
return (int32_t)parent->OtherPid();
|
return (int32_t)parent->OtherPid();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UtilityProcessParent* GetParent() const {
|
RefPtr<UtilityProcessParent> GetParent() const { return mParent; }
|
||||||
if (RefPtr<UtilityProcessManager> utilitypm =
|
|
||||||
UtilityProcessManager::GetSingleton()) {
|
RefPtr<UtilityProcessParent> mParent = nullptr;
|
||||||
if (UtilityProcessParent* parent = utilitypm->GetProcessParent()) {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~UtilityMemoryReporter() = default;
|
~UtilityMemoryReporter() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
RefPtr<MemoryReportingProcess>
|
RefPtr<MemoryReportingProcess> UtilityProcessManager::GetProcessMemoryReporter(
|
||||||
UtilityProcessManager::GetProcessMemoryReporter() {
|
UtilityProcessParent* parent) {
|
||||||
if (!mProcess || !mProcess->IsConnected()) {
|
return new UtilityMemoryReporter(parent);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return new UtilityMemoryReporter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla::ipc
|
} // namespace mozilla::ipc
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
#define _include_ipc_glue_UtilityProcessManager_h_
|
#define _include_ipc_glue_UtilityProcessManager_h_
|
||||||
#include "mozilla/MozPromise.h"
|
#include "mozilla/MozPromise.h"
|
||||||
#include "mozilla/ipc/UtilityProcessHost.h"
|
#include "mozilla/ipc/UtilityProcessHost.h"
|
||||||
|
#include "mozilla/EnumeratedArray.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
@ -36,27 +38,54 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
|
||||||
|
|
||||||
void OnProcessUnexpectedShutdown(UtilityProcessHost* aHost);
|
void OnProcessUnexpectedShutdown(UtilityProcessHost* aHost);
|
||||||
|
|
||||||
// Returns the platform pid for the Utility process.
|
// Returns the platform pid for this utility sandbox process.
|
||||||
Maybe<base::ProcessId> ProcessPid();
|
Maybe<base::ProcessId> ProcessPid(SandboxingKind aSandbox);
|
||||||
|
|
||||||
// If a Utility process is present, create a MemoryReportingProcess object.
|
// Create a MemoryReportingProcess object for this utility process
|
||||||
// Otherwise, return null.
|
RefPtr<MemoryReportingProcess> GetProcessMemoryReporter(
|
||||||
RefPtr<MemoryReportingProcess> GetProcessMemoryReporter();
|
UtilityProcessParent* parent);
|
||||||
|
|
||||||
// Returns access to the PUtility protocol if a Utility process is present.
|
// Returns access to the PUtility protocol if a Utility process for that
|
||||||
UtilityProcessParent* GetProcessParent() { return mProcessParent; }
|
// sandbox is present.
|
||||||
|
RefPtr<UtilityProcessParent> GetProcessParent(SandboxingKind aSandbox) {
|
||||||
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (!p) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return p->mProcessParent;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the Utility Process
|
// Get a list of all valid utility process parent references
|
||||||
UtilityProcessHost* Process() { return mProcess; }
|
nsTArray<RefPtr<UtilityProcessParent>> GetAllProcessesProcessParent() {
|
||||||
|
nsTArray<RefPtr<UtilityProcessParent>> rv;
|
||||||
|
for (auto& p : mProcesses) {
|
||||||
|
if (p && p->mProcessParent) {
|
||||||
|
rv.AppendElement(p->mProcessParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
// Shutdown the Utility process.
|
// Returns the Utility Process for that sandbox
|
||||||
void CleanShutdown();
|
UtilityProcessHost* Process(SandboxingKind aSandbox) {
|
||||||
|
RefPtr<ProcessFields> p = GetProcess(aSandbox);
|
||||||
|
if (!p) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return p->mProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown the Utility process for that sandbox.
|
||||||
|
void CleanShutdown(SandboxingKind aSandbox);
|
||||||
|
|
||||||
|
// Shutdown all utility processes
|
||||||
|
void CleanShutdownAllProcesses();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~UtilityProcessManager();
|
~UtilityProcessManager();
|
||||||
|
|
||||||
bool IsProcessLaunching();
|
bool IsProcessLaunching(SandboxingKind aSandbox);
|
||||||
bool IsProcessDestroyed() const;
|
bool IsProcessDestroyed(SandboxingKind aSandbox);
|
||||||
|
|
||||||
// Called from our xpcom-shutdown observer.
|
// Called from our xpcom-shutdown observer.
|
||||||
void OnXPCOMShutdown();
|
void OnXPCOMShutdown();
|
||||||
|
@ -64,7 +93,7 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
|
||||||
|
|
||||||
UtilityProcessManager();
|
UtilityProcessManager();
|
||||||
|
|
||||||
void DestroyProcess();
|
void DestroyProcess(SandboxingKind aSandbox);
|
||||||
|
|
||||||
bool IsShutdown() const;
|
bool IsShutdown() const;
|
||||||
|
|
||||||
|
@ -82,19 +111,41 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
|
||||||
friend class Observer;
|
friend class Observer;
|
||||||
|
|
||||||
RefPtr<Observer> mObserver;
|
RefPtr<Observer> mObserver;
|
||||||
uint32_t mNumProcessAttempts = 0;
|
|
||||||
uint32_t mNumUnexpectedCrashes = 0;
|
|
||||||
|
|
||||||
// Fields that are associated with the current Utility process.
|
class ProcessFields final {
|
||||||
UtilityProcessHost* mProcess = nullptr;
|
public:
|
||||||
UtilityProcessParent* mProcessParent = nullptr;
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProcessFields);
|
||||||
// Collects any pref changes that occur during process launch (after
|
|
||||||
// the initial map is passed in command-line arguments) to be sent
|
explicit ProcessFields(SandboxingKind aSandbox) : mSandbox(aSandbox){};
|
||||||
// when the process can receive IPC messages.
|
|
||||||
nsTArray<dom::Pref> mQueuedPrefs;
|
// Promise will be resolved when this Utility process has been fully started
|
||||||
// Promise will be resolved when the Utility process has been fully started
|
// and configured. Only accessed on the main thread.
|
||||||
// and VideoBridge configured. Only accessed on the main thread.
|
RefPtr<GenericNonExclusivePromise> mLaunchPromise;
|
||||||
RefPtr<GenericNonExclusivePromise> mLaunchPromise;
|
|
||||||
|
uint32_t mNumProcessAttempts = 0;
|
||||||
|
uint32_t mNumUnexpectedCrashes = 0;
|
||||||
|
|
||||||
|
// Fields that are associated with the current Utility process.
|
||||||
|
UtilityProcessHost* mProcess = nullptr;
|
||||||
|
RefPtr<UtilityProcessParent> mProcessParent = nullptr;
|
||||||
|
|
||||||
|
// Collects any pref changes that occur during process launch (after
|
||||||
|
// the initial map is passed in command-line arguments) to be sent
|
||||||
|
// when the process can receive IPC messages.
|
||||||
|
nsTArray<dom::Pref> mQueuedPrefs;
|
||||||
|
|
||||||
|
SandboxingKind mSandbox = SandboxingKind::COUNT;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~ProcessFields() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumeratedArray<SandboxingKind, SandboxingKind::COUNT, RefPtr<ProcessFields>>
|
||||||
|
mProcesses;
|
||||||
|
|
||||||
|
RefPtr<ProcessFields> GetProcess(SandboxingKind);
|
||||||
|
bool NoMoreProcesses();
|
||||||
|
uint16_t AliveProcesses();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|
|
@ -39,7 +39,8 @@ bool UtilityProcessParent::SendRequestMemoryReport(
|
||||||
[&](const uint32_t& aGeneration2) {
|
[&](const uint32_t& aGeneration2) {
|
||||||
if (RefPtr<UtilityProcessManager> utilitypm =
|
if (RefPtr<UtilityProcessManager> utilitypm =
|
||||||
UtilityProcessManager::GetSingleton()) {
|
UtilityProcessManager::GetSingleton()) {
|
||||||
if (UtilityProcessParent* parent = utilitypm->GetProcessParent()) {
|
for (RefPtr<UtilityProcessParent>& parent :
|
||||||
|
utilitypm->GetAllProcessesProcessParent()) {
|
||||||
if (parent->mMemoryReportRequest) {
|
if (parent->mMemoryReportRequest) {
|
||||||
parent->mMemoryReportRequest->Finish(aGeneration2);
|
parent->mMemoryReportRequest->Finish(aGeneration2);
|
||||||
parent->mMemoryReportRequest = nullptr;
|
parent->mMemoryReportRequest = nullptr;
|
||||||
|
@ -50,7 +51,8 @@ bool UtilityProcessParent::SendRequestMemoryReport(
|
||||||
[&](mozilla::ipc::ResponseRejectReason) {
|
[&](mozilla::ipc::ResponseRejectReason) {
|
||||||
if (RefPtr<UtilityProcessManager> utilitypm =
|
if (RefPtr<UtilityProcessManager> utilitypm =
|
||||||
UtilityProcessManager::GetSingleton()) {
|
UtilityProcessManager::GetSingleton()) {
|
||||||
if (UtilityProcessParent* parent = utilitypm->GetProcessParent()) {
|
for (RefPtr<UtilityProcessParent>& parent :
|
||||||
|
utilitypm->GetAllProcessesProcessParent()) {
|
||||||
parent->mMemoryReportRequest = nullptr;
|
parent->mMemoryReportRequest = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ add_task(async () => {
|
||||||
aAmount,
|
aAmount,
|
||||||
aDescription
|
aDescription
|
||||||
) {
|
) {
|
||||||
const expectedProcess = `Utility (pid ${utilityPid})`;
|
const expectedProcess = `Utility (pid: ${utilityPid}, sandboxingKind: ${kGenericUtility})`;
|
||||||
if (aProcess !== expectedProcess) {
|
if (aProcess !== expectedProcess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,11 @@ add_task(async () => {
|
||||||
await TestUtils.waitForCondition(async () => {
|
await TestUtils.waitForCondition(async () => {
|
||||||
profile = await Services.profiler.getProfileDataAsync();
|
profile = await Services.profiler.getProfileDataAsync();
|
||||||
return (
|
return (
|
||||||
profile.processes.filter(ps => ps.threads[0].processType === "utility")
|
// Search for process name to not be disturbed by other types of utility
|
||||||
.length === 1
|
// e.g. Utility AudioDecoder
|
||||||
|
profile.processes.filter(
|
||||||
|
ps => ps.threads[0].processName === "Utility Process"
|
||||||
|
).length === 1
|
||||||
);
|
);
|
||||||
}, "Give time for the profiler to start and collect some samples");
|
}, "Give time for the profiler to start and collect some samples");
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,8 @@ TEST_F(UtilityProcess, NoProcess) {
|
||||||
UtilityProcessManager::GetSingleton();
|
UtilityProcessManager::GetSingleton();
|
||||||
EXPECT_NE(utilityProc, nullptr);
|
EXPECT_NE(utilityProc, nullptr);
|
||||||
|
|
||||||
Maybe<int32_t> noPid = utilityProc->ProcessPid();
|
Maybe<int32_t> noPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
ASSERT_TRUE(noPid.isNothing());
|
ASSERT_TRUE(noPid.isNothing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +84,8 @@ TEST_F(UtilityProcess, LaunchProcess) {
|
||||||
[&]() mutable {
|
[&]() mutable {
|
||||||
EXPECT_TRUE(true);
|
EXPECT_TRUE(true);
|
||||||
|
|
||||||
Maybe<int32_t> utilityPid = utilityProc->ProcessPid();
|
Maybe<int32_t> utilityPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
EXPECT_TRUE(utilityPid.isSome());
|
EXPECT_TRUE(utilityPid.isSome());
|
||||||
EXPECT_GE(*utilityPid, 1);
|
EXPECT_GE(*utilityPid, 1);
|
||||||
EXPECT_NE(*utilityPid, thisPid);
|
EXPECT_NE(*utilityPid, thisPid);
|
||||||
|
@ -110,13 +112,15 @@ TEST_F(UtilityProcess, DestroyProcess) {
|
||||||
->Then(
|
->Then(
|
||||||
GetCurrentSerialEventTarget(), __func__,
|
GetCurrentSerialEventTarget(), __func__,
|
||||||
[&]() {
|
[&]() {
|
||||||
Maybe<int32_t> utilityPid = utilityProc->ProcessPid();
|
Maybe<int32_t> utilityPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
EXPECT_TRUE(utilityPid.isSome());
|
EXPECT_TRUE(utilityPid.isSome());
|
||||||
EXPECT_GE(*utilityPid, 1);
|
EXPECT_GE(*utilityPid, 1);
|
||||||
|
|
||||||
utilityProc->CleanShutdown();
|
utilityProc->CleanShutdown(SandboxingKind::GENERIC_UTILITY);
|
||||||
|
|
||||||
utilityPid = utilityProc->ProcessPid();
|
utilityPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
EXPECT_TRUE(utilityPid.isNothing());
|
EXPECT_TRUE(utilityPid.isNothing());
|
||||||
|
|
||||||
EXPECT_TRUE(true);
|
EXPECT_TRUE(true);
|
||||||
|
|
|
@ -35,7 +35,8 @@ UtilityProcessTest::StartProcess(JSContext* aCx,
|
||||||
->Then(
|
->Then(
|
||||||
GetCurrentSerialEventTarget(), __func__,
|
GetCurrentSerialEventTarget(), __func__,
|
||||||
[promise, utilityProc]() {
|
[promise, utilityProc]() {
|
||||||
Maybe<int32_t> utilityPid = utilityProc->ProcessPid();
|
Maybe<int32_t> utilityPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
if (utilityPid.isSome()) {
|
if (utilityPid.isSome()) {
|
||||||
promise->MaybeResolve(*utilityPid);
|
promise->MaybeResolve(*utilityPid);
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,8 +59,9 @@ UtilityProcessTest::StopProcess() {
|
||||||
UtilityProcessManager::GetSingleton();
|
UtilityProcessManager::GetSingleton();
|
||||||
MOZ_ASSERT(utilityProc, "No UtilityprocessManager?");
|
MOZ_ASSERT(utilityProc, "No UtilityprocessManager?");
|
||||||
|
|
||||||
utilityProc->CleanShutdown();
|
utilityProc->CleanShutdown(SandboxingKind::GENERIC_UTILITY);
|
||||||
Maybe<int32_t> utilityPid = utilityProc->ProcessPid();
|
Maybe<int32_t> utilityPid =
|
||||||
|
utilityProc->ProcessPid(SandboxingKind::GENERIC_UTILITY);
|
||||||
MOZ_RELEASE_ASSERT(utilityPid.isNothing(),
|
MOZ_RELEASE_ASSERT(utilityPid.isNothing(),
|
||||||
"Should not have a utility process PID anymore");
|
"Should not have a utility process PID anymore");
|
||||||
|
|
||||||
|
|
|
@ -258,11 +258,13 @@ SandboxTest::StartTests(const nsTArray<nsCString>& aProcessesList) {
|
||||||
utilityProc->LaunchProcess(sandboxingKind)
|
utilityProc->LaunchProcess(sandboxingKind)
|
||||||
->Then(
|
->Then(
|
||||||
GetMainThreadSerialEventTarget(), __func__,
|
GetMainThreadSerialEventTarget(), __func__,
|
||||||
[processPromise, utilityProc]() {
|
[processPromise, utilityProc, sandboxingKind]() {
|
||||||
UtilityProcessParent* utilityParent =
|
RefPtr<UtilityProcessParent> utilityParent =
|
||||||
utilityProc ? utilityProc->GetProcessParent() : nullptr;
|
utilityProc
|
||||||
|
? utilityProc->GetProcessParent(sandboxingKind)
|
||||||
|
: nullptr;
|
||||||
if (utilityParent) {
|
if (utilityParent) {
|
||||||
return InitializeSandboxTestingActors(utilityParent,
|
return InitializeSandboxTestingActors(utilityParent.get(),
|
||||||
processPromise);
|
processPromise);
|
||||||
}
|
}
|
||||||
return processPromise->Reject(NS_ERROR_FAILURE, __func__);
|
return processPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "mozilla/ipc/UtilityProcessChild.h"
|
#include "mozilla/ipc/UtilityProcessChild.h"
|
||||||
#include "mozilla/ipc/UtilityProcessManager.h"
|
#include "mozilla/ipc/UtilityProcessManager.h"
|
||||||
#include "mozilla/ipc/UtilityProcessParent.h"
|
#include "mozilla/ipc/UtilityProcessParent.h"
|
||||||
|
#include "mozilla/ipc/UtilityProcessSandboxing.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "GMPPlatform.h"
|
#include "GMPPlatform.h"
|
||||||
#include "GMPServiceParent.h"
|
#include "GMPServiceParent.h"
|
||||||
|
@ -233,9 +234,9 @@ void FlushAllChildData(
|
||||||
|
|
||||||
if (RefPtr<UtilityProcessManager> utilityManager =
|
if (RefPtr<UtilityProcessManager> utilityManager =
|
||||||
UtilityProcessManager::GetIfExists()) {
|
UtilityProcessManager::GetIfExists()) {
|
||||||
if (UtilityProcessParent* utilityParent =
|
for (RefPtr<UtilityProcessParent>& parent :
|
||||||
utilityManager->GetProcessParent()) {
|
utilityManager->GetAllProcessesProcessParent()) {
|
||||||
promises.EmplaceBack(utilityParent->SendFlushFOGData());
|
promises.EmplaceBack(parent->SendFlushFOGData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +363,7 @@ void TestTriggerMetrics(uint32_t aProcessType,
|
||||||
break;
|
break;
|
||||||
case nsIXULRuntime::PROCESS_TYPE_UTILITY:
|
case nsIXULRuntime::PROCESS_TYPE_UTILITY:
|
||||||
Unused << ipc::UtilityProcessManager::GetSingleton()
|
Unused << ipc::UtilityProcessManager::GetSingleton()
|
||||||
->GetProcessParent()
|
->GetProcessParent(ipc::SandboxingKind::GENERIC_UTILITY)
|
||||||
->SendTestTriggerMetrics()
|
->SendTestTriggerMetrics()
|
||||||
->Then(
|
->Then(
|
||||||
GetCurrentSerialEventTarget(), __func__,
|
GetCurrentSerialEventTarget(), __func__,
|
||||||
|
|
|
@ -1816,9 +1816,12 @@ nsresult nsMemoryReporterManager::StartGettingReports() {
|
||||||
|
|
||||||
if (RefPtr<UtilityProcessManager> utility =
|
if (RefPtr<UtilityProcessManager> utility =
|
||||||
UtilityProcessManager::GetIfExists()) {
|
UtilityProcessManager::GetIfExists()) {
|
||||||
if (RefPtr<MemoryReportingProcess> proc =
|
for (RefPtr<UtilityProcessParent>& parent :
|
||||||
utility->GetProcessMemoryReporter()) {
|
utility->GetAllProcessesProcessParent()) {
|
||||||
s->mChildrenPending.AppendElement(proc.forget());
|
if (RefPtr<MemoryReportingProcess> proc =
|
||||||
|
utility->GetProcessMemoryReporter(parent)) {
|
||||||
|
s->mChildrenPending.AppendElement(proc.forget());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче