Bug 1704500: Add WindowsUtils kind of utility process on Windows r=gerard-majax,ipc-reviewers,nika

Adds a new type of utility process that is set up to handle Windows OS objects.  We are adding this process type to run Windows geolocation APIs but more services are expected to be included in it.  The ILocation APIs have a race condition that would otherwise crash the main process.  The ILocation work is in a later patch in the series.

Depends on D155017

Differential Revision: https://phabricator.services.mozilla.com/D155018
This commit is contained in:
David Parks 2023-01-31 21:10:26 +00:00
parent 04713ddc93
commit 2e959c2130
15 changed files with 229 additions and 11 deletions

View File

@ -1071,7 +1071,7 @@ static WebIDLUtilityActorName UtilityActorNameToWebIDL(
mozilla::UtilityActorName aType) {
// Max is the value of the last enum, not the length, so add one.
static_assert(WebIDLUtilityActorNameValues::Count ==
static_cast<size_t>(UtilityActorName::JSOracle) + 1,
static_cast<size_t>(UtilityActorName::WindowsUtils) + 1,
"In order for this static cast to be okay, "
"UtilityActorName must match UtilityActorName exactly");
@ -1084,6 +1084,7 @@ static WebIDLUtilityActorName UtilityActorNameToWebIDL(
UTILITYACTORNAME_TO_WEBIDL_CASE(AudioDecoder_WMF, AudioDecoder_WMF);
UTILITYACTORNAME_TO_WEBIDL_CASE(MfMediaEngineCDM, MfMediaEngineCDM);
UTILITYACTORNAME_TO_WEBIDL_CASE(JSOracle, JSOracle);
UTILITYACTORNAME_TO_WEBIDL_CASE(WindowsUtils, WindowsUtils);
}
MOZ_ASSERT(false, "Unhandled case in WebIDLUtilityActorName");

View File

@ -728,6 +728,7 @@ enum WebIDLUtilityActorName {
"audioDecoder_WMF",
"mfMediaEngineCDM",
"jSOracle",
"windowsUtils",
};
dictionary UtilityActorsDictionary {

View File

@ -0,0 +1,15 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* 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/. */
namespace mozilla {
namespace dom {
// Manager of utility actors that run in the windows utility process.
protocol PWindowsUtils {
};
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,24 @@
/* -*- 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/. */
#ifndef mozilla_dom_WindowsUtilsChild_h__
#define mozilla_dom_WindowsUtilsChild_h__
#include "mozilla/dom/PWindowsUtilsChild.h"
namespace mozilla::dom {
// Manager for utilities in the WindowsUtils utility process.
class WindowsUtilsChild final : public PWindowsUtilsChild {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowsUtilsChild, override);
protected:
~WindowsUtilsChild() = default;
};
} // namespace mozilla::dom
#endif // mozilla_dom_WindowsUtilsChild_h__

View File

@ -0,0 +1,52 @@
/* -*- 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/. */
#ifndef mozilla_dom_WindowsUtilsParent_h__
#define mozilla_dom_WindowsUtilsParent_h__
#include "mozilla/dom/PWindowsUtilsParent.h"
#include "mozilla/ProcInfo.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/UtilityProcessParent.h"
namespace mozilla::dom {
// Main-process manager for utilities in the WindowsUtils utility process.
class WindowsUtilsParent final : public PWindowsUtilsParent {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowsUtilsParent, override);
nsresult BindToUtilityProcess(
RefPtr<mozilla::ipc::UtilityProcessParent> aUtilityParent) {
Endpoint<PWindowsUtilsParent> parentEnd;
Endpoint<PWindowsUtilsChild> childEnd;
nsresult rv = PWindowsUtils::CreateEndpoints(base::GetCurrentProcId(),
aUtilityParent->OtherPid(),
&parentEnd, &childEnd);
if (NS_FAILED(rv)) {
MOZ_ASSERT(false, "Protocol endpoints failure");
return NS_ERROR_FAILURE;
}
if (!aUtilityParent->SendStartWindowsUtilsService(std::move(childEnd))) {
MOZ_ASSERT(false, "SendStartWindowsUtilsService failed");
return NS_ERROR_FAILURE;
}
DebugOnly<bool> ok = parentEnd.Bind(this);
MOZ_ASSERT(ok);
return NS_OK;
}
UtilityActorName GetActorName() { return UtilityActorName::WindowsUtils; }
protected:
~WindowsUtilsParent() = default;
};
} // namespace mozilla::dom
#endif // mozilla_dom_WindowsUtilsParent_h__

View File

@ -4,8 +4,22 @@
# 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/.
SOURCES += ["nsHapticFeedback.cpp", "WindowsLocationProvider.cpp"]
EXPORTS.mozilla.dom += [
"WindowsUtilsChild.h",
"WindowsUtilsParent.h",
]
UNIFIED_SOURCES += [
"nsHapticFeedback.cpp",
"WindowsLocationProvider.cpp",
]
IPDL_SOURCES += [
"PWindowsUtils.ipdl",
]
LOCAL_INCLUDES += ["/dom/geolocation"]
include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = "xul"

View File

@ -10,6 +10,10 @@ include protocol PProfiler;
include protocol PUtilityAudioDecoder;
include protocol PJSOracle;
#if defined(XP_WIN)
include protocol PWindowsUtils;
#endif
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
include protocol PSandboxTesting;
#endif
@ -85,6 +89,10 @@ child:
async StartJSOracleService(Endpoint<PJSOracleChild> aEndpoint);
#if defined(XP_WIN)
async StartWindowsUtilsService(Endpoint<PWindowsUtilsChild> aEndpoint);
#endif
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)
async InitSandboxTesting(Endpoint<PSandboxTestingChild> aEndpoint);
#endif

View File

@ -28,6 +28,7 @@
#if defined(XP_WIN)
# include "mozilla/WinDllServices.h"
# include "mozilla/dom/WindowsUtilsChild.h"
#endif
#include "nsDebugImpl.h"
@ -249,6 +250,20 @@ mozilla::ipc::IPCResult UtilityProcessChild::RecvStartJSOracleService(
return IPC_OK();
}
#ifdef XP_WIN
mozilla::ipc::IPCResult UtilityProcessChild::RecvStartWindowsUtilsService(
Endpoint<dom::PWindowsUtilsChild>&& aEndpoint) {
mWindowsUtilsInstance = new dom::WindowsUtilsChild();
if (!mWindowsUtilsInstance) {
return IPC_FAIL(this, "Failed to create WindowsUtilsChild");
}
[[maybe_unused]] bool ok = std::move(aEndpoint).Bind(mWindowsUtilsInstance);
MOZ_ASSERT(ok);
return IPC_OK();
}
#endif
void UtilityProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
if (AbnormalShutdown == aWhy) {
NS_WARNING("Shutting down Utility process early due to a crash!");

View File

@ -63,6 +63,11 @@ class UtilityProcessChild final : public PUtilityProcessChild {
mozilla::ipc::IPCResult RecvStartJSOracleService(
Endpoint<dom::PJSOracleChild>&& aEndpoint);
#ifdef XP_WIN
mozilla::ipc::IPCResult RecvStartWindowsUtilsService(
Endpoint<PWindowsUtilsChild>&& aEndpoint);
#endif
AsyncBlockers& AsyncShutdownService() { return mShutdownBlockers; }
void ActorDestroy(ActorDestroyReason aWhy) override;
@ -80,6 +85,10 @@ class UtilityProcessChild final : public PUtilityProcessChild {
RefPtr<ChildProfilerController> mProfilerController;
RefPtr<UtilityAudioDecoderParent> mUtilityAudioDecoderInstance{};
RefPtr<dom::JSOracleChild> mJSOracleInstance{};
#ifdef XP_WIN
RefPtr<PWindowsUtilsChild> mWindowsUtilsInstance;
#endif
AsyncBlockers mShutdownBlockers;
};

View File

@ -21,6 +21,10 @@
#include "nsAppRunner.h"
#include "nsContentUtils.h"
#ifdef XP_WIN
# include "mozilla/dom/WindowsUtilsParent.h"
#endif
#include "mozilla/GeckoArgs.h"
namespace mozilla::ipc {
@ -373,6 +377,44 @@ UtilityProcessManager::StartJSOracle(dom::JSOracleParent* aParent) {
return StartUtility(RefPtr{aParent}, SandboxingKind::GENERIC_UTILITY);
}
#ifdef XP_WIN
// Windows Utils
RefPtr<UtilityProcessManager::WindowsUtilsPromise>
UtilityProcessManager::GetWindowsUtilsPromise() {
RefPtr<UtilityProcessManager> self = this;
if (!mWindowsUtils) {
mWindowsUtils = new dom::WindowsUtilsParent();
}
RefPtr<dom::WindowsUtilsParent> wup = mWindowsUtils;
MOZ_ASSERT(wup, "Unable to get a singleton for WindowsUtils");
return StartUtility(wup, SandboxingKind::WINDOWS_UTILS)
->Then(
GetMainThreadSerialEventTarget(), __func__,
[self, wup]() {
if (!wup->CanSend()) {
MOZ_ASSERT(false, "WindowsUtilsParent can't send");
return WindowsUtilsPromise::CreateAndReject(NS_ERROR_FAILURE,
__func__);
}
return WindowsUtilsPromise::CreateAndResolve(wup, __func__);
},
[self](nsresult aError) {
if (!self->IsShutdown()) {
MOZ_ASSERT_UNREACHABLE(
"PWindowsUtils: failure when starting actor");
}
NS_WARNING("StartUtility rejected promise for PWindowsUtils");
return WindowsUtilsPromise::CreateAndReject(aError, __func__);
});
}
void UtilityProcessManager::ReleaseWindowsUtils() { mWindowsUtils = nullptr; }
#endif // XP_WIN
bool UtilityProcessManager::IsProcessLaunching(SandboxingKind aSandbox) {
MOZ_ASSERT(NS_IsMainThread());

View File

@ -20,7 +20,8 @@ class MemoryReportingProcess;
namespace dom {
class JSOracleParent;
}
class WindowsUtilsParent;
} // namespace dom
namespace ipc {
@ -37,6 +38,9 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
MozPromise<Endpoint<PRemoteDecoderManagerChild>, nsresult, true>;
using JSOraclePromise = GenericNonExclusivePromise;
using WindowsUtilsPromise =
MozPromise<RefPtr<dom::WindowsUtilsParent>, nsresult, true>;
static void Initialize();
static void Shutdown();
@ -56,6 +60,15 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
RefPtr<JSOraclePromise> StartJSOracle(mozilla::dom::JSOracleParent* aParent);
#ifdef XP_WIN
// Get the (possibly already resolved) promise for the Windows utility
// process actor. Creates the process if it is not running.
RefPtr<WindowsUtilsPromise> GetWindowsUtilsPromise();
// Releases the WindowsUtils actor so that it can be destroyed.
// Subsequent attempts to use WindowsUtils will create a new process.
void ReleaseWindowsUtils();
#endif
void OnProcessUnexpectedShutdown(UtilityProcessHost* aHost);
// Returns the platform pid for this utility sandbox process.
@ -197,6 +210,10 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener {
RefPtr<ProcessFields> GetProcess(SandboxingKind);
bool NoMoreProcesses();
uint16_t AliveProcesses();
#ifdef XP_WIN
RefPtr<dom::WindowsUtilsParent> mWindowsUtils;
#endif // XP_WIN
};
} // namespace ipc

View File

@ -27,6 +27,10 @@ enum SandboxingKind : uint64_t {
#ifdef MOZ_WMF_MEDIA_ENGINE
MF_MEDIA_ENGINE_CDM,
#endif
#ifdef XP_WIN
WINDOWS_UTILS,
#endif
COUNT,
};

View File

@ -75,6 +75,7 @@ enum class UtilityActorName {
AudioDecoder_WMF,
MfMediaEngineCDM,
JSOracle,
WindowsUtils,
};
// String that will be used e.g. to annotate crash reports

View File

@ -55,6 +55,8 @@ nsCString GetUtilityActorName(const UtilityActorName aActorName) {
return "mf-media-engine"_ns;
case UtilityActorName::JSOracle:
return "js-oracle"_ns;
case UtilityActorName::WindowsUtils:
return "windows-utils"_ns;
}
return "unknown"_ns;
}

View File

@ -16,6 +16,7 @@
#include "mozilla/ChaosMode.h"
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/ipc/UtilityProcessChild.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryChecking.h"
#include "mozilla/Poison.h"
@ -5976,16 +5977,28 @@ bool XRE_IsE10sParentProcess() {
#undef GECKO_PROCESS_TYPE
bool XRE_UseNativeEventProcessing() {
switch (XRE_GetProcessType()) {
#if defined(XP_MACOSX) || defined(XP_WIN)
if (XRE_IsRDDProcess() || XRE_IsSocketProcess() || XRE_IsUtilityProcess()) {
return false;
case GeckoProcessType_RDD:
case GeckoProcessType_Socket:
return false;
case GeckoProcessType_Utility: {
# if defined(XP_WIN)
auto upc = mozilla::ipc::UtilityProcessChild::Get();
MOZ_ASSERT(upc);
// WindowsUtils is for Windows APIs, which typically require a Windows
// native event loop.
return upc->mSandbox == mozilla::ipc::SandboxingKind::WINDOWS_UTILS;
# else
return false;
# endif // defined(XP_WIN)
}
#endif // defined(XP_MACOSX) || defined(XP_WIN)
case GeckoProcessType_Content:
return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
default:
return true;
}
#endif
if (XRE_IsContentProcess()) {
return StaticPrefs::dom_ipc_useNativeEventProcessing_content();
}
return true;
}
namespace mozilla {