зеркало из https://github.com/mozilla/gecko-dev.git
265 строки
8.1 KiB
C++
265 строки
8.1 KiB
C++
/* -*- 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/. */
|
|
#include "UtilityProcessChild.h"
|
|
|
|
#include "mozilla/ipc/UtilityProcessManager.h"
|
|
#include "mozilla/ipc/UtilityProcessSandboxing.h"
|
|
#include "mozilla/dom/ContentParent.h"
|
|
#include "mozilla/dom/MemoryReportRequest.h"
|
|
#include "mozilla/ipc/CrashReporterClient.h"
|
|
#include "mozilla/ipc/Endpoint.h"
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
|
# include "mozilla/Sandbox.h"
|
|
#endif
|
|
|
|
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
|
|
# include "mozilla/SandboxTestingChild.h"
|
|
#endif
|
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#if defined(XP_WIN)
|
|
# include "mozilla/WinDllServices.h"
|
|
#endif
|
|
|
|
#include "nsDebugImpl.h"
|
|
#include "nsIXULRuntime.h"
|
|
#include "nsThreadManager.h"
|
|
#include "GeckoProfiler.h"
|
|
|
|
#include "mozilla/ipc/ProcessChild.h"
|
|
#include "mozilla/FOGIPC.h"
|
|
#include "mozilla/glean/GleanMetrics.h"
|
|
|
|
namespace mozilla::ipc {
|
|
|
|
using namespace layers;
|
|
|
|
static StaticMutex sUtilityProcessChildMutex;
|
|
static StaticRefPtr<UtilityProcessChild> sUtilityProcessChild;
|
|
|
|
UtilityProcessChild::UtilityProcessChild() {
|
|
nsDebugImpl::SetMultiprocessMode("Utility");
|
|
StaticMutexAutoLock lock(sUtilityProcessChildMutex);
|
|
sUtilityProcessChild = this;
|
|
}
|
|
|
|
UtilityProcessChild::~UtilityProcessChild() = default;
|
|
|
|
/* static */
|
|
RefPtr<UtilityProcessChild> UtilityProcessChild::GetSingleton() {
|
|
StaticMutexAutoLock lock(sUtilityProcessChildMutex);
|
|
if (!sUtilityProcessChild) {
|
|
sUtilityProcessChild = new UtilityProcessChild();
|
|
}
|
|
return sUtilityProcessChild;
|
|
}
|
|
|
|
/* static */
|
|
RefPtr<UtilityProcessChild> UtilityProcessChild::Get() {
|
|
StaticMutexAutoLock lock(sUtilityProcessChildMutex);
|
|
return sUtilityProcessChild;
|
|
}
|
|
|
|
bool UtilityProcessChild::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
|
|
const nsCString& aParentBuildID,
|
|
uint64_t aSandboxingKind) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Initialize the thread manager before starting IPC. Otherwise, messages
|
|
// may be posted to the main thread and we won't be able to process them.
|
|
if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
|
|
return false;
|
|
}
|
|
|
|
// Now it's safe to start IPC.
|
|
if (NS_WARN_IF(!aEndpoint.Bind(this))) {
|
|
return false;
|
|
}
|
|
|
|
// This must be checked before any IPDL message, which may hit sentinel
|
|
// errors due to parent and content processes having different
|
|
// versions.
|
|
MessageChannel* channel = GetIPCChannel();
|
|
if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID.get())) {
|
|
// We need to quit this process if the buildID doesn't match the parent's.
|
|
// This can occur when an update occurred in the background.
|
|
ipc::ProcessChild::QuickExit();
|
|
}
|
|
|
|
// Init crash reporter support.
|
|
ipc::CrashReporterClient::InitSingleton(this);
|
|
|
|
if (NS_FAILED(NS_InitMinimalXPCOM())) {
|
|
return false;
|
|
}
|
|
|
|
mSandbox = (SandboxingKind)aSandboxingKind;
|
|
|
|
profiler_set_process_name(nsCString("Utility Process"));
|
|
|
|
// Notify the parent process that we have finished our init and that it can
|
|
// now resolve the pending promise of process startup
|
|
SendInitCompleted();
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
|
|
extern "C" {
|
|
void CGSShutdownServerConnections();
|
|
};
|
|
#endif
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvInit(
|
|
const Maybe<FileDescriptor>& aBrokerFd,
|
|
const bool& aCanRecordReleaseTelemetry) {
|
|
// Do this now (before closing WindowServer on macOS) to avoid risking
|
|
// blocking in GetCurrentProcess() called on that platform
|
|
mozilla::ipc::SetThisProcessName("Utility Process");
|
|
|
|
#if defined(MOZ_SANDBOX)
|
|
# if defined(XP_MACOSX)
|
|
// Close all current connections to the WindowServer. This ensures that the
|
|
// Activity Monitor will not label the content process as "Not responding"
|
|
// because it's not running a native event loop. See bug 1384336.
|
|
CGSShutdownServerConnections();
|
|
|
|
# elif defined(XP_LINUX)
|
|
int fd = -1;
|
|
if (aBrokerFd.isSome()) {
|
|
fd = aBrokerFd.value().ClonePlatformHandle().release();
|
|
}
|
|
|
|
SetUtilitySandbox(fd, mSandbox);
|
|
|
|
# endif // XP_MACOSX/XP_LINUX
|
|
#endif // MOZ_SANDBOX
|
|
|
|
#if defined(XP_WIN)
|
|
if (aCanRecordReleaseTelemetry) {
|
|
RefPtr<DllServices> dllSvc(DllServices::Get());
|
|
dllSvc->StartUntrustedModulesProcessor(false);
|
|
}
|
|
#endif // defined(XP_WIN)
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvPreferenceUpdate(
|
|
const Pref& aPref) {
|
|
Preferences::SetPreference(aPref);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvInitProfiler(
|
|
Endpoint<PProfilerChild>&& aEndpoint) {
|
|
mProfilerController = ChildProfilerController::Create(std::move(aEndpoint));
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvRequestMemoryReport(
|
|
const uint32_t& aGeneration, const bool& aAnonymize,
|
|
const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile,
|
|
const RequestMemoryReportResolver& aResolver) {
|
|
nsPrintfCString processName("Utility (pid: %" PRIPID
|
|
", sandboxingKind: %" PRIu64 ")",
|
|
base::GetCurrentProcId(), mSandbox);
|
|
|
|
mozilla::dom::MemoryReportRequestClient::Start(
|
|
aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName,
|
|
[&](const MemoryReport& aReport) {
|
|
Unused << GetSingleton()->SendAddMemoryReport(aReport);
|
|
},
|
|
aResolver);
|
|
return IPC_OK();
|
|
}
|
|
|
|
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvInitSandboxTesting(
|
|
Endpoint<PSandboxTestingChild>&& aEndpoint) {
|
|
if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) {
|
|
return IPC_FAIL(
|
|
this, "InitSandboxTesting failed to initialise the child process.");
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
#endif
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvFlushFOGData(
|
|
FlushFOGDataResolver&& aResolver) {
|
|
glean::FlushFOGData(std::move(aResolver));
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult UtilityProcessChild::RecvTestTriggerMetrics(
|
|
TestTriggerMetricsResolver&& aResolve) {
|
|
mozilla::glean::test_only_ipc::a_counter.Add(
|
|
nsIXULRuntime::PROCESS_TYPE_UTILITY);
|
|
aResolve(true);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
UtilityProcessChild::RecvStartUtilityAudioDecoderService(
|
|
Endpoint<PUtilityAudioDecoderParent>&& aEndpoint) {
|
|
mUtilityAudioDecoderInstance = new UtilityAudioDecoderParent();
|
|
if (!mUtilityAudioDecoderInstance) {
|
|
return IPC_FAIL(this, "Failing to create UtilityAudioDecoderParent");
|
|
}
|
|
|
|
mUtilityAudioDecoderInstance->Start(std::move(aEndpoint));
|
|
return IPC_OK();
|
|
}
|
|
|
|
void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
|
|
if (AbnormalShutdown == aWhy) {
|
|
NS_WARNING("Shutting down Utility process early due to a crash!");
|
|
ipc::ProcessChild::QuickExit();
|
|
}
|
|
|
|
// Send the last bits of Glean data over to the main process.
|
|
glean::FlushFOGData(
|
|
[](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); });
|
|
|
|
#ifndef NS_FREE_PERMANENT_DATA
|
|
ProcessChild::QuickExit();
|
|
#else
|
|
|
|
if (mProfilerController) {
|
|
mProfilerController->Shutdown();
|
|
mProfilerController = nullptr;
|
|
}
|
|
|
|
// Wait until all RemoteDecoderManagerParent have closed.
|
|
//
|
|
// FIXME: Should move from using AsyncBlockers to proper
|
|
// nsIAsyncShutdownService once it is not JS, see bug 1760855
|
|
mShutdownBlockers.WaitUntilClear(10 * 1000 /* 10s timeout*/)
|
|
->Then(GetCurrentSerialEventTarget(), __func__, [&]() {
|
|
# ifdef XP_WIN
|
|
{
|
|
RefPtr<DllServices> dllSvc(DllServices::Get());
|
|
dllSvc->DisableFull();
|
|
}
|
|
# endif // defined(XP_WIN)
|
|
|
|
{
|
|
StaticMutexAutoLock lock(sUtilityProcessChildMutex);
|
|
if (sUtilityProcessChild) {
|
|
sUtilityProcessChild = nullptr;
|
|
}
|
|
}
|
|
|
|
ipc::CrashReporterClient::DestroySingleton();
|
|
XRE_ShutdownChildProcess();
|
|
});
|
|
#endif // NS_FREE_PERMANENT_DATA
|
|
}
|
|
|
|
} // namespace mozilla::ipc
|