From 2e959c21307a5a6f8d64478b63ff63e06a7c6de9 Mon Sep 17 00:00:00 2001 From: David Parks Date: Tue, 31 Jan 2023 21:10:26 +0000 Subject: [PATCH] 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 --- dom/base/ChromeUtils.cpp | 3 +- dom/chrome-webidl/ChromeUtils.webidl | 1 + dom/system/windows/PWindowsUtils.ipdl | 15 ++++++ dom/system/windows/WindowsUtilsChild.h | 24 +++++++++ dom/system/windows/WindowsUtilsParent.h | 52 +++++++++++++++++++ dom/system/windows/moz.build | 16 +++++- ipc/glue/PUtilityProcess.ipdl | 8 +++ ipc/glue/UtilityProcessChild.cpp | 15 ++++++ ipc/glue/UtilityProcessChild.h | 9 ++++ ipc/glue/UtilityProcessManager.cpp | 42 +++++++++++++++ ipc/glue/UtilityProcessManager.h | 19 ++++++- ipc/glue/UtilityProcessSandboxing.h | 4 ++ toolkit/components/processtools/ProcInfo.h | 1 + .../processtools/ProcInfo_common.cpp | 2 + toolkit/xre/nsAppRunner.cpp | 29 ++++++++--- 15 files changed, 229 insertions(+), 11 deletions(-) create mode 100644 dom/system/windows/PWindowsUtils.ipdl create mode 100644 dom/system/windows/WindowsUtilsChild.h create mode 100644 dom/system/windows/WindowsUtilsParent.h diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp index 8f58ddf397ef..1917fd994271 100644 --- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -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(UtilityActorName::JSOracle) + 1, + static_cast(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"); diff --git a/dom/chrome-webidl/ChromeUtils.webidl b/dom/chrome-webidl/ChromeUtils.webidl index f8f0b02ee7c3..5b417e0c139d 100644 --- a/dom/chrome-webidl/ChromeUtils.webidl +++ b/dom/chrome-webidl/ChromeUtils.webidl @@ -728,6 +728,7 @@ enum WebIDLUtilityActorName { "audioDecoder_WMF", "mfMediaEngineCDM", "jSOracle", + "windowsUtils", }; dictionary UtilityActorsDictionary { diff --git a/dom/system/windows/PWindowsUtils.ipdl b/dom/system/windows/PWindowsUtils.ipdl new file mode 100644 index 000000000000..98fc516fbc4a --- /dev/null +++ b/dom/system/windows/PWindowsUtils.ipdl @@ -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 diff --git a/dom/system/windows/WindowsUtilsChild.h b/dom/system/windows/WindowsUtilsChild.h new file mode 100644 index 000000000000..4f1bbff99cb5 --- /dev/null +++ b/dom/system/windows/WindowsUtilsChild.h @@ -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__ diff --git a/dom/system/windows/WindowsUtilsParent.h b/dom/system/windows/WindowsUtilsParent.h new file mode 100644 index 000000000000..bc447a116759 --- /dev/null +++ b/dom/system/windows/WindowsUtilsParent.h @@ -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 aUtilityParent) { + Endpoint parentEnd; + Endpoint 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 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__ diff --git a/dom/system/windows/moz.build b/dom/system/windows/moz.build index 45131af39e92..b04f5c352cfc 100644 --- a/dom/system/windows/moz.build +++ b/dom/system/windows/moz.build @@ -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" diff --git a/ipc/glue/PUtilityProcess.ipdl b/ipc/glue/PUtilityProcess.ipdl index a42e708a6a40..c40e3247f43e 100644 --- a/ipc/glue/PUtilityProcess.ipdl +++ b/ipc/glue/PUtilityProcess.ipdl @@ -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 aEndpoint); +#if defined(XP_WIN) + async StartWindowsUtilsService(Endpoint aEndpoint); +#endif + #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) async InitSandboxTesting(Endpoint aEndpoint); #endif diff --git a/ipc/glue/UtilityProcessChild.cpp b/ipc/glue/UtilityProcessChild.cpp index 93dacfa28eb6..22e5e4275ee7 100644 --- a/ipc/glue/UtilityProcessChild.cpp +++ b/ipc/glue/UtilityProcessChild.cpp @@ -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&& 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!"); diff --git a/ipc/glue/UtilityProcessChild.h b/ipc/glue/UtilityProcessChild.h index eadded6f1bff..5a646c4d72c0 100644 --- a/ipc/glue/UtilityProcessChild.h +++ b/ipc/glue/UtilityProcessChild.h @@ -63,6 +63,11 @@ class UtilityProcessChild final : public PUtilityProcessChild { mozilla::ipc::IPCResult RecvStartJSOracleService( Endpoint&& aEndpoint); +#ifdef XP_WIN + mozilla::ipc::IPCResult RecvStartWindowsUtilsService( + Endpoint&& aEndpoint); +#endif + AsyncBlockers& AsyncShutdownService() { return mShutdownBlockers; } void ActorDestroy(ActorDestroyReason aWhy) override; @@ -80,6 +85,10 @@ class UtilityProcessChild final : public PUtilityProcessChild { RefPtr mProfilerController; RefPtr mUtilityAudioDecoderInstance{}; RefPtr mJSOracleInstance{}; +#ifdef XP_WIN + RefPtr mWindowsUtilsInstance; +#endif + AsyncBlockers mShutdownBlockers; }; diff --git a/ipc/glue/UtilityProcessManager.cpp b/ipc/glue/UtilityProcessManager.cpp index 1af6a06e3d21..945ae97ebaa1 100644 --- a/ipc/glue/UtilityProcessManager.cpp +++ b/ipc/glue/UtilityProcessManager.cpp @@ -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::GetWindowsUtilsPromise() { + RefPtr self = this; + if (!mWindowsUtils) { + mWindowsUtils = new dom::WindowsUtilsParent(); + } + + RefPtr 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()); diff --git a/ipc/glue/UtilityProcessManager.h b/ipc/glue/UtilityProcessManager.h index 70c763546c66..bcedbdc9753a 100644 --- a/ipc/glue/UtilityProcessManager.h +++ b/ipc/glue/UtilityProcessManager.h @@ -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, nsresult, true>; using JSOraclePromise = GenericNonExclusivePromise; + using WindowsUtilsPromise = + MozPromise, nsresult, true>; + static void Initialize(); static void Shutdown(); @@ -56,6 +60,15 @@ class UtilityProcessManager final : public UtilityProcessHost::Listener { RefPtr 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 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 GetProcess(SandboxingKind); bool NoMoreProcesses(); uint16_t AliveProcesses(); + +#ifdef XP_WIN + RefPtr mWindowsUtils; +#endif // XP_WIN }; } // namespace ipc diff --git a/ipc/glue/UtilityProcessSandboxing.h b/ipc/glue/UtilityProcessSandboxing.h index 2c644bf044fe..7aac77e0e993 100644 --- a/ipc/glue/UtilityProcessSandboxing.h +++ b/ipc/glue/UtilityProcessSandboxing.h @@ -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, }; diff --git a/toolkit/components/processtools/ProcInfo.h b/toolkit/components/processtools/ProcInfo.h index ce4bd1d9b2df..5f565de2f65e 100644 --- a/toolkit/components/processtools/ProcInfo.h +++ b/toolkit/components/processtools/ProcInfo.h @@ -75,6 +75,7 @@ enum class UtilityActorName { AudioDecoder_WMF, MfMediaEngineCDM, JSOracle, + WindowsUtils, }; // String that will be used e.g. to annotate crash reports diff --git a/toolkit/components/processtools/ProcInfo_common.cpp b/toolkit/components/processtools/ProcInfo_common.cpp index 5a44775cb7cc..3936f3cee983 100644 --- a/toolkit/components/processtools/ProcInfo_common.cpp +++ b/toolkit/components/processtools/ProcInfo_common.cpp @@ -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; } diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 3f80ad2a9b19..5e413296f08c 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -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 {