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
Родитель 04713ddc93
Коммит 2e959c2130
15 изменённых файлов: 229 добавлений и 11 удалений

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

@ -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");

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

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

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

@ -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

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

@ -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__

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

@ -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__

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

@ -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"

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

@ -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

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

@ -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!");

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

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

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

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

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

@ -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

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

@ -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,
};

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

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

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

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

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

@ -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 {