Bug 1753424 - Support running multiple UtilityProcess r=nika

Differential Revision: https://phabricator.services.mozilla.com/D139817
This commit is contained in:
Alexandre Lissy 2022-03-26 09:53:47 +00:00
Родитель 6c667ad60a
Коммит baebfcdc76
13 изменённых файлов: 268 добавлений и 127 удалений

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

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