Bug 1756518 - Delay starting UntrustedModulesProcessor. r=mhowell,necko-reviewers,kershaw

This patch is to delay starting `UntrustedModulesProcessor` to avoid
processing a massive amount of loaded modules in the browser process
during startup.

To achive that, this patch introduces "unblock-untrusted-modules-thread"
notification.  Before the notification, `UntrustedModulesProcessor` is
created but marked as not ready.  This means the processor does not
go beyond `ScheduleNonEmptyQueueProcessing`.  Once the notification is
observed, we propagate it to all existing child processes, and afterward
`UntrustedModulesProcessor` in new processes will be marked ready from
the beginning.

Differential Revision: https://phabricator.services.mozilla.com/D140123
This commit is contained in:
Toshihito Kikuchi 2022-03-04 21:12:18 +00:00
parent ed39c78974
commit c601fd8b0a
21 changed files with 220 additions and 70 deletions

View File

@ -2766,6 +2766,16 @@ BrowserGlue.prototype = {
}, },
}, },
{
condition: AppConstants.platform == "win",
task: () => {
Services.obs.notifyObservers(
null,
"unblock-untrusted-modules-thread"
);
},
},
// WebDriver components (Remote Agent and Marionette) need to be // WebDriver components (Remote Agent and Marionette) need to be
// initialized as very last step. // initialized as very last step.
{ {

View File

@ -676,7 +676,8 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList, FullLookAndFeel&& aLookAndFeelData, dom::SystemFontList&& aFontList,
Maybe<SharedMemoryHandle>&& aSharedUASheetHandle, Maybe<SharedMemoryHandle>&& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress, const uintptr_t& aSharedUASheetAddress,
nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks) { nsTArray<SharedMemoryHandle>&& aSharedFontListBlocks,
const bool& aIsReadyForBackgroundProcessing) {
if (!sShutdownCanary) { if (!sShutdownCanary) {
return IPC_OK(); return IPC_OK();
} }
@ -691,7 +692,8 @@ mozilla::ipc::IPCResult ContentChild::RecvSetXPCOMProcessAttributes(
gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates()); gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
InitSharedUASheets(std::move(aSharedUASheetHandle), aSharedUASheetAddress); InitSharedUASheets(std::move(aSharedUASheetHandle), aSharedUASheetAddress);
InitXPCOM(std::move(aXPCOMInit), aInitialData); InitXPCOM(std::move(aXPCOMInit), aInitialData,
aIsReadyForBackgroundProcessing);
InitGraphicsDeviceData(aXPCOMInit.contentDeviceData()); InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
return IPC_OK(); return IPC_OK();
@ -1323,7 +1325,8 @@ void ContentChild::InitSharedUASheets(Maybe<SharedMemoryHandle>&& aHandle,
void ContentChild::InitXPCOM( void ContentChild::InitXPCOM(
XPCOMInitData&& aXPCOMInit, XPCOMInitData&& aXPCOMInit,
const mozilla::dom::ipc::StructuredCloneData& aInitialData) { const mozilla::dom::ipc::StructuredCloneData& aInitialData,
bool aIsReadyForBackgroundProcessing) {
#ifdef MOZ_WIDGET_GTK #ifdef MOZ_WIDGET_GTK
// LookAndFeel::NativeInit takes a long time to run on Linux, here we schedule // LookAndFeel::NativeInit takes a long time to run on Linux, here we schedule
// it as soon as possible after BackgroundChild::Startup to give // it as soon as possible after BackgroundChild::Startup to give
@ -1336,7 +1339,7 @@ void ContentChild::InitXPCOM(
// DLL services untrusted modules processing depends on // DLL services untrusted modules processing depends on
// BackgroundChild::Startup having been called // BackgroundChild::Startup having been called
RefPtr<DllServices> dllSvc(DllServices::Get()); RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(); dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread(); PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
@ -1463,6 +1466,14 @@ mozilla::ipc::IPCResult ContentChild::RecvGetUntrustedModulesData(
[aResolver](nsresult aReason) { aResolver(Nothing()); }); [aResolver](nsresult aReason) { aResolver(Nothing()); });
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult ContentChild::RecvUnblockUntrustedModulesThread() {
if (nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService()) {
obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
}
return IPC_OK();
}
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
PCycleCollectWithLogsChild* ContentChild::AllocPCycleCollectWithLogsChild( PCycleCollectWithLogsChild* ContentChild::AllocPCycleCollectWithLogsChild(

View File

@ -124,7 +124,8 @@ class ContentChild final : public PContentChild,
bool aIsForBrowser); bool aIsForBrowser);
void InitXPCOM(XPCOMInitData&& aXPCOMInit, void InitXPCOM(XPCOMInitData&& aXPCOMInit,
const mozilla::dom::ipc::StructuredCloneData& aInitialData); const mozilla::dom::ipc::StructuredCloneData& aInitialData,
bool aIsReadyForBackgroundProcessing);
void InitSharedUASheets(Maybe<base::SharedMemoryHandle>&& aHandle, void InitSharedUASheets(Maybe<base::SharedMemoryHandle>&& aHandle,
uintptr_t aAddress); uintptr_t aAddress);
@ -538,6 +539,7 @@ class ContentChild final : public PContentChild,
#if defined(XP_WIN) #if defined(XP_WIN)
mozilla::ipc::IPCResult RecvGetUntrustedModulesData( mozilla::ipc::IPCResult RecvGetUntrustedModulesData(
GetUntrustedModulesDataResolver&& aResolver); GetUntrustedModulesDataResolver&& aResolver);
mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes( mozilla::ipc::IPCResult RecvSetXPCOMProcessAttributes(
@ -545,7 +547,8 @@ class ContentChild final : public PContentChild,
FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList, FullLookAndFeel&& aLookAndFeelData, SystemFontList&& aFontList,
Maybe<base::SharedMemoryHandle>&& aSharedUASheetHandle, Maybe<base::SharedMemoryHandle>&& aSharedUASheetHandle,
const uintptr_t& aSharedUASheetAddress, const uintptr_t& aSharedUASheetAddress,
nsTArray<base::SharedMemoryHandle>&& aSharedFontListBlocks); nsTArray<base::SharedMemoryHandle>&& aSharedFontListBlocks,
const bool& aIsReadyForBackgroundProcessing);
mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile( mozilla::ipc::IPCResult RecvProvideAnonymousTemporaryFile(
const uint64_t& aID, const FileDescOrError& aFD); const uint64_t& aID, const FileDescOrError& aFD);

View File

@ -2990,9 +2990,16 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) {
sharedUASheetAddress = 0; sharedUASheetAddress = 0;
} }
bool isReadyForBackgroundProcessing = false;
#if defined(XP_WIN)
RefPtr<DllServices> dllSvc(DllServices::Get());
isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
#endif
Unused << SendSetXPCOMProcessAttributes( Unused << SendSetXPCOMProcessAttributes(
xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle), xpcomInit, initialData, lnf, fontList, std::move(sharedUASheetHandle),
sharedUASheetAddress, std::move(sharedFontListBlocks)); sharedUASheetAddress, std::move(sharedFontListBlocks),
isReadyForBackgroundProcessing);
ipc::WritableSharedMap* sharedData = ipc::WritableSharedMap* sharedData =
nsFrameMessageManager::sParentProcessManager->SharedData(); nsFrameMessageManager::sParentProcessManager->SharedData();

View File

@ -580,6 +580,13 @@ child:
* to pull data from content processes. * to pull data from content processes.
*/ */
async GetUntrustedModulesData() returns (UntrustedModulesData? data); async GetUntrustedModulesData() returns (UntrustedModulesData? data);
/**
* This method is used to notifty a child process to start
* processing module loading events in UntrustedModulesProcessor.
* This should be called when the parent process has gone idle.
*/
async UnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
/** /**
@ -750,7 +757,8 @@ child:
SystemFontList systemFontList, SystemFontList systemFontList,
SharedMemoryHandle? sharedUASheetHandle, SharedMemoryHandle? sharedUASheetHandle,
uintptr_t sharedUASheetAddress, uintptr_t sharedUASheetAddress,
SharedMemoryHandle[] sharedFontListBlocks); SharedMemoryHandle[] sharedFontListBlocks,
bool aIsStartingUp);
// Notify child that last-pb-context-exited notification was observed // Notify child that last-pb-context-exited notification was observed
async LastPrivateDocShellDestroyed(); async LastPrivateDocShellDestroyed();

View File

@ -38,7 +38,8 @@ protocol PRDD
parent: parent:
async Init(GfxVarUpdate[] vars, FileDescriptor? sandboxBroker, async Init(GfxVarUpdate[] vars, FileDescriptor? sandboxBroker,
bool canRecordReleaseTelemetry); bool canRecordReleaseTelemetry,
bool aIsReadyForBackgroundProcessing);
async InitProfiler(Endpoint<PProfilerChild> endpoint); async InitProfiler(Endpoint<PProfilerChild> endpoint);
@ -61,6 +62,13 @@ parent:
#if defined(XP_WIN) #if defined(XP_WIN)
async GetUntrustedModulesData() returns (UntrustedModulesData? data); async GetUntrustedModulesData() returns (UntrustedModulesData? data);
/**
* This method is used to notifty a child process to start
* processing module loading events in UntrustedModulesProcessor.
* This should be called when the parent process has gone idle.
*/
async UnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) #if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS)

View File

@ -59,7 +59,14 @@ bool RDDChild::Init() {
nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars(); nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars();
SendInit(updates, brokerFd, Telemetry::CanRecordReleaseData()); bool isReadyForBackgroundProcessing = false;
#if defined(XP_WIN)
RefPtr<DllServices> dllSvc(DllServices::Get());
isReadyForBackgroundProcessing = dllSvc->IsReadyForBackgroundProcessing();
#endif
SendInit(updates, brokerFd, Telemetry::CanRecordReleaseData(),
isReadyForBackgroundProcessing);
Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid())); Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));

View File

@ -124,7 +124,8 @@ void CGSShutdownServerConnections();
mozilla::ipc::IPCResult RDDParent::RecvInit( mozilla::ipc::IPCResult RDDParent::RecvInit(
nsTArray<GfxVarUpdate>&& vars, const Maybe<FileDescriptor>& aBrokerFd, nsTArray<GfxVarUpdate>&& vars, const Maybe<FileDescriptor>& aBrokerFd,
const bool& aCanRecordReleaseTelemetry) { const bool& aCanRecordReleaseTelemetry,
const bool& aIsReadyForBackgroundProcessing) {
for (const auto& var : vars) { for (const auto& var : vars) {
gfxVars::ApplyUpdate(var); gfxVars::ApplyUpdate(var);
} }
@ -151,7 +152,7 @@ mozilla::ipc::IPCResult RDDParent::RecvInit(
#if defined(XP_WIN) #if defined(XP_WIN)
if (aCanRecordReleaseTelemetry) { if (aCanRecordReleaseTelemetry) {
RefPtr<DllServices> dllSvc(DllServices::Get()); RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(); dllSvc->StartUntrustedModulesProcessor(aIsReadyForBackgroundProcessing);
} }
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
return IPC_OK(); return IPC_OK();
@ -247,6 +248,14 @@ mozilla::ipc::IPCResult RDDParent::RecvGetUntrustedModulesData(
[aResolver](nsresult aReason) { aResolver(Nothing()); }); [aResolver](nsresult aReason) { aResolver(Nothing()); });
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult RDDParent::RecvUnblockUntrustedModulesThread() {
if (nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService()) {
obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
}
return IPC_OK();
}
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
mozilla::ipc::IPCResult RDDParent::RecvPreferenceUpdate(const Pref& aPref) { mozilla::ipc::IPCResult RDDParent::RecvPreferenceUpdate(const Pref& aPref) {

View File

@ -29,7 +29,8 @@ class RDDParent final : public PRDDParent {
mozilla::ipc::IPCResult RecvInit(nsTArray<GfxVarUpdate>&& vars, mozilla::ipc::IPCResult RecvInit(nsTArray<GfxVarUpdate>&& vars,
const Maybe<ipc::FileDescriptor>& aBrokerFd, const Maybe<ipc::FileDescriptor>& aBrokerFd,
const bool& aCanRecordReleaseTelemetry); const bool& aCanRecordReleaseTelemetry,
const bool& aIsReadyForBackgroundProcessing);
mozilla::ipc::IPCResult RecvInitProfiler( mozilla::ipc::IPCResult RecvInitProfiler(
Endpoint<PProfilerChild>&& aEndpoint); Endpoint<PProfilerChild>&& aEndpoint);
@ -47,6 +48,7 @@ class RDDParent final : public PRDDParent {
#if defined(XP_WIN) #if defined(XP_WIN)
mozilla::ipc::IPCResult RecvGetUntrustedModulesData( mozilla::ipc::IPCResult RecvGetUntrustedModulesData(
GetUntrustedModulesDataResolver&& aResolver); GetUntrustedModulesDataResolver&& aResolver);
mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& pref); mozilla::ipc::IPCResult RecvPreferenceUpdate(const Pref& pref);
mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref); mozilla::ipc::IPCResult RecvUpdateVar(const GfxVarUpdate& pref);

View File

@ -138,7 +138,7 @@ mozilla::ipc::IPCResult UtilityProcessChild::RecvInit(
#if defined(XP_WIN) #if defined(XP_WIN)
if (aCanRecordReleaseTelemetry) { if (aCanRecordReleaseTelemetry) {
RefPtr<DllServices> dllSvc(DllServices::Get()); RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(); dllSvc->StartUntrustedModulesProcessor(false);
} }
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
return IPC_OK(); return IPC_OK();

View File

@ -1318,7 +1318,7 @@ int XRE_XPCShellMain(int argc, char** argv, char** envp,
// Ensure that DLL Services are running // Ensure that DLL Services are running
RefPtr<DllServices> dllSvc(DllServices::Get()); RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(); dllSvc->StartUntrustedModulesProcessor(true);
auto dllServicesDisable = auto dllServicesDisable =
MakeScopeExit([&dllSvc]() { dllSvc->DisableFull(); }); MakeScopeExit([&dllSvc]() { dllSvc->DisableFull(); });

View File

@ -85,6 +85,9 @@ struct SocketPorcessInitAttributes {
bool mOffline; bool mOffline;
bool mConnectivity; bool mConnectivity;
bool mInitSandbox; bool mInitSandbox;
#if defined(XP_WIN)
bool mIsReadyForBackgroundProcessing;
#endif
FileDescriptor? mSandboxBroker; FileDescriptor? mSandboxBroker;
}; };
@ -222,6 +225,13 @@ child:
#if defined(XP_WIN) #if defined(XP_WIN)
async GetUntrustedModulesData() returns (UntrustedModulesData? data); async GetUntrustedModulesData() returns (UntrustedModulesData? data);
/**
* This method is used to notifty a child process to start
* processing module loading events in UntrustedModulesProcessor.
* This should be called when the parent process has gone idle.
*/
async UnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
both: both:

View File

@ -169,11 +169,6 @@ bool SocketProcessChild::Init(base::ProcessId aParentPid,
return false; return false;
} }
#if defined(XP_WIN)
RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor();
#endif // defined(XP_WIN)
return true; return true;
} }
@ -228,6 +223,12 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvInit(
Unused << RecvInitLinuxSandbox(aAttributes.mSandboxBroker()); Unused << RecvInitLinuxSandbox(aAttributes.mSandboxBroker());
} }
#if defined(XP_WIN)
RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(
aAttributes.mIsReadyForBackgroundProcessing());
#endif // defined(XP_WIN)
return IPC_OK(); return IPC_OK();
} }
@ -740,6 +741,15 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvGetUntrustedModulesData(
[aResolver](nsresult aReason) { aResolver(Nothing()); }); [aResolver](nsresult aReason) { aResolver(Nothing()); });
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
SocketProcessChild::RecvUnblockUntrustedModulesThread() {
if (nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService()) {
obs->NotifyObservers(nullptr, "unblock-untrusted-modules-thread", nullptr);
}
return IPC_OK();
}
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
} // namespace net } // namespace net

View File

@ -160,6 +160,7 @@ class SocketProcessChild final
#if defined(XP_WIN) #if defined(XP_WIN)
mozilla::ipc::IPCResult RecvGetUntrustedModulesData( mozilla::ipc::IPCResult RecvGetUntrustedModulesData(
GetUntrustedModulesDataResolver&& aResolver); GetUntrustedModulesDataResolver&& aResolver);
mozilla::ipc::IPCResult RecvUnblockUntrustedModulesThread();
#endif // defined(XP_WIN) #endif // defined(XP_WIN)
protected: protected:

View File

@ -176,6 +176,12 @@ void SocketProcessHost::InitAfterConnect(bool aSucceeded) {
attributes.mInitSandbox() = false; attributes.mInitSandbox() = false;
#if defined(XP_WIN)
RefPtr<DllServices> dllSvc(DllServices::Get());
attributes.mIsReadyForBackgroundProcessing() =
dllSvc->IsReadyForBackgroundProcessing();
#endif
#if defined(XP_LINUX) && defined(MOZ_SANDBOX) #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
if (GetEffectiveSocketProcessSandboxLevel() > 0) { if (GetEffectiveSocketProcessSandboxLevel() > 0) {
auto policy = SandboxBrokerPolicyFactory::GetSocketProcessPolicy( auto policy = SandboxBrokerPolicyFactory::GetSocketProcessPolicy(

View File

@ -11,9 +11,13 @@
#include "mozilla/CmdLineAndEnvUtils.h" #include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/net/SocketProcessChild.h" #include "mozilla/net/SocketProcessChild.h"
#include "mozilla/net/SocketProcessParent.h"
#include "mozilla/RDDChild.h"
#include "mozilla/RDDParent.h" #include "mozilla/RDDParent.h"
#include "mozilla/RDDProcessManager.h"
#include "mozilla/ScopeExit.h" #include "mozilla/ScopeExit.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
@ -106,12 +110,14 @@ bool UntrustedModulesProcessor::IsSupportedProcessType() {
} }
/* static */ /* static */
RefPtr<UntrustedModulesProcessor> UntrustedModulesProcessor::Create() { RefPtr<UntrustedModulesProcessor> UntrustedModulesProcessor::Create(
bool aIsReadyForBackgroundProcessing) {
if (!IsSupportedProcessType()) { if (!IsSupportedProcessType()) {
return nullptr; return nullptr;
} }
RefPtr<UntrustedModulesProcessor> result(new UntrustedModulesProcessor()); RefPtr<UntrustedModulesProcessor> result(
new UntrustedModulesProcessor(aIsReadyForBackgroundProcessing));
return result.forget(); return result.forget();
} }
@ -119,14 +125,16 @@ NS_IMPL_ISUPPORTS(UntrustedModulesProcessor, nsIObserver)
static const uint32_t kThreadTimeoutMS = 120000; // 2 minutes static const uint32_t kThreadTimeoutMS = 120000; // 2 minutes
UntrustedModulesProcessor::UntrustedModulesProcessor() UntrustedModulesProcessor::UntrustedModulesProcessor(
bool aIsReadyForBackgroundProcessing)
: mThread(new LazyIdleThread(kThreadTimeoutMS, "Untrusted Modules"_ns, : mThread(new LazyIdleThread(kThreadTimeoutMS, "Untrusted Modules"_ns,
LazyIdleThread::ManualShutdown)), LazyIdleThread::ManualShutdown)),
mUnprocessedMutex( mUnprocessedMutex(
"mozilla::UntrustedModulesProcessor::mUnprocessedMutex"), "mozilla::UntrustedModulesProcessor::mUnprocessedMutex"),
mModuleCacheMutex( mModuleCacheMutex(
"mozilla::UntrustedModulesProcessor::mModuleCacheMutex"), "mozilla::UntrustedModulesProcessor::mModuleCacheMutex"),
mAllowProcessing(true) { mStatus(aIsReadyForBackgroundProcessing ? Status::Allowed
: Status::StartingUp) {
AddObservers(); AddObservers();
} }
@ -134,17 +142,22 @@ void UntrustedModulesProcessor::AddObservers() {
nsCOMPtr<nsIObserverService> obsServ(services::GetObserverService()); nsCOMPtr<nsIObserverService> obsServ(services::GetObserverService());
obsServ->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false); obsServ->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
obsServ->AddObserver(this, "xpcom-shutdown-threads", false); obsServ->AddObserver(this, "xpcom-shutdown-threads", false);
obsServ->AddObserver(this, "unblock-untrusted-modules-thread", false);
if (XRE_IsContentProcess()) { if (XRE_IsContentProcess()) {
obsServ->AddObserver(this, "content-child-will-shutdown", false); obsServ->AddObserver(this, "content-child-will-shutdown", false);
} }
} }
bool UntrustedModulesProcessor::IsReadyForBackgroundProcessing() const {
return mStatus == Status::Allowed;
}
void UntrustedModulesProcessor::Disable() { void UntrustedModulesProcessor::Disable() {
// Ensure that mThread cannot run at low priority anymore // Ensure that mThread cannot run at low priority anymore
BackgroundPriorityRegion::Clear(mThread); BackgroundPriorityRegion::Clear(mThread);
// No more background processing allowed beyond this point // No more background processing allowed beyond this point
if (!mAllowProcessing.exchange(false)) { if (mStatus.exchange(Status::ShuttingDown) != Status::Allowed) {
return; return;
} }
@ -171,6 +184,37 @@ NS_IMETHODIMP UntrustedModulesProcessor::Observe(nsISupports* aSubject,
return NS_OK; return NS_OK;
} }
if (!strcmp(aTopic, "unblock-untrusted-modules-thread")) {
nsCOMPtr<nsIObserverService> obs(services::GetObserverService());
obs->RemoveObserver(this, "unblock-untrusted-modules-thread");
mStatus.compareExchange(Status::StartingUp, Status::Allowed);
if (!IsReadyForBackgroundProcessing()) {
// If we're shutting down, stop here.
return NS_OK;
}
if (XRE_IsParentProcess()) {
// Propagate notification to child processes
nsTArray<dom::ContentParent*> contentProcesses;
dom::ContentParent::GetAll(contentProcesses);
for (auto* proc : contentProcesses) {
Unused << proc->SendUnblockUntrustedModulesThread();
}
if (auto* proc = net::SocketProcessParent::GetSingleton()) {
Unused << proc->SendUnblockUntrustedModulesThread();
}
if (auto* rddMgr = RDDProcessManager::Get()) {
if (auto* proc = rddMgr->GetRDDChild()) {
Unused << proc->SendUnblockUntrustedModulesThread();
}
}
}
return NS_OK;
}
MOZ_ASSERT_UNREACHABLE("Not reachable"); MOZ_ASSERT_UNREACHABLE("Not reachable");
return NS_OK; return NS_OK;
@ -180,6 +224,7 @@ void UntrustedModulesProcessor::RemoveObservers() {
nsCOMPtr<nsIObserverService> obsServ(services::GetObserverService()); nsCOMPtr<nsIObserverService> obsServ(services::GetObserverService());
obsServ->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID); obsServ->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
obsServ->RemoveObserver(this, "xpcom-shutdown-threads"); obsServ->RemoveObserver(this, "xpcom-shutdown-threads");
obsServ->RemoveObserver(this, "unblock-untrusted-modules-thread");
if (XRE_IsContentProcess()) { if (XRE_IsContentProcess()) {
obsServ->RemoveObserver(this, "content-child-will-shutdown"); obsServ->RemoveObserver(this, "content-child-will-shutdown");
} }
@ -204,7 +249,7 @@ void UntrustedModulesProcessor::ScheduleNonEmptyQueueProcessing(
return; return;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -241,7 +286,7 @@ void UntrustedModulesProcessor::CancelScheduledProcessing(
void UntrustedModulesProcessor::DispatchBackgroundProcessing() { void UntrustedModulesProcessor::DispatchBackgroundProcessing() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -254,7 +299,7 @@ void UntrustedModulesProcessor::DispatchBackgroundProcessing() {
void UntrustedModulesProcessor::Enqueue( void UntrustedModulesProcessor::Enqueue(
glue::EnhancedModuleLoadInfo&& aModLoadInfo) { glue::EnhancedModuleLoadInfo&& aModLoadInfo) {
if (!mAllowProcessing) { if (mStatus == Status::ShuttingDown) {
return; return;
} }
@ -272,7 +317,7 @@ void UntrustedModulesProcessor::Enqueue(
} }
void UntrustedModulesProcessor::Enqueue(ModuleLoadInfoVec&& aEvents) { void UntrustedModulesProcessor::Enqueue(ModuleLoadInfoVec&& aEvents) {
if (!mAllowProcessing) { if (mStatus == Status::ShuttingDown) {
return; return;
} }
@ -315,7 +360,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrust(
ModulePaths&& aModPaths, bool aRunAtNormalPriority) { ModulePaths&& aModPaths, bool aRunAtNormalPriority) {
MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread()); MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return ModulesTrustPromise::CreateAndReject( return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -403,7 +448,7 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() {
self = std::move(self), source, self = std::move(self), source,
whenProcessed = std::move(whenProcessed)]() { whenProcessed = std::move(whenProcessed)]() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!self->mAllowProcessing) { if (!self->IsReadyForBackgroundProcessing()) {
// We can't do any more work, just reject all the things // We can't do any more work, just reject all the things
whenProcessed->Then( whenProcessed->Then(
GetMainThreadSerialEventTarget(), source, GetMainThreadSerialEventTarget(), source,
@ -442,13 +487,13 @@ UntrustedModulesProcessor::GetProcessedDataInternalChildProcess() {
} }
void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueue() { void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueue() {
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
BackgroundPriorityRegion bgRgn; BackgroundPriorityRegion bgRgn;
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -502,7 +547,7 @@ void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueueChildProcess() {
self = std::move(self), source, self = std::move(self), source,
whenProcessed = std::move(whenProcessed)]() { whenProcessed = std::move(whenProcessed)]() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!self->mAllowProcessing) { if (!self->IsReadyForBackgroundProcessing()) {
// We can't do any more work, just no-op // We can't do any more work, just no-op
whenProcessed->Then( whenProcessed->Then(
GetMainThreadSerialEventTarget(), source, GetMainThreadSerialEventTarget(), source,
@ -514,7 +559,7 @@ void UntrustedModulesProcessor::BackgroundProcessModuleLoadQueueChildProcess() {
whenProcessed->Then( whenProcessed->Then(
evtTarget, source, evtTarget, source,
[self = std::move(self)](Maybe<ModulesMapResultWithLoads>&& aResult) { [self = std::move(self)](Maybe<ModulesMapResultWithLoads>&& aResult) {
if (aResult.isNothing() || !self->mAllowProcessing) { if (aResult.isNothing() || !self->IsReadyForBackgroundProcessing()) {
// Nothing to do // Nothing to do
return; return;
} }
@ -565,9 +610,9 @@ UntrustedModulesProcessor::ExtractLoadingEventsToProcess(size_t aMaxLength) {
return loadsToProcess; return loadsToProcess;
} }
// This function contains multiple |mAllowProcessing| checks so that we can // This function contains multiple IsReadyForBackgroundProcessing() checks so
// quickly bail out at the first sign of shutdown. This may be important when // that we can quickly bail out at the first sign of shutdown. This may be
// the current thread is running under background priority. // important when the current thread is running under background priority.
void UntrustedModulesProcessor::ProcessModuleLoadQueue() { void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
AssertRunningOnLazyIdleThread(); AssertRunningOnLazyIdleThread();
if (!XRE_IsParentProcess()) { if (!XRE_IsParentProcess()) {
@ -577,7 +622,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
LoadsVec loadsToProcess = LoadsVec loadsToProcess =
ExtractLoadingEventsToProcess(UntrustedModulesData::kMaxEvents); ExtractLoadingEventsToProcess(UntrustedModulesData::kMaxEvents);
if (!mAllowProcessing || loadsToProcess.empty()) { if (!IsReadyForBackgroundProcessing() || loadsToProcess.empty()) {
return; return;
} }
@ -595,7 +640,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
uint32_t trustTestFailures = 0; uint32_t trustTestFailures = 0;
for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) { for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) {
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -608,7 +653,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -623,7 +668,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -639,14 +684,14 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
mProcessedModuleLoads.mModules.LookupOrInsert( mProcessedModuleLoads.mModules.LookupOrInsert(
event.mModule->mResolvedNtName, event.mModule); event.mModule->mResolvedNtName, event.mModule);
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
Telemetry::ProcessedStack processedStack = Telemetry::ProcessedStack processedStack =
stackProcessor.GetStackAndModules(backtrace); stackProcessor.GetStackAndModules(backtrace);
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -661,7 +706,7 @@ void UntrustedModulesProcessor::ProcessModuleLoadQueue() {
return; return;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -741,7 +786,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
return GetModulesTrustPromise::CreateAndResolve(Nothing(), __func__); return GetModulesTrustPromise::CreateAndResolve(Nothing(), __func__);
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return GetModulesTrustPromise::CreateAndReject( return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -750,7 +795,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
// Build a set of modules to be processed by the parent // Build a set of modules to be processed by the parent
for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) { for (glue::EnhancedModuleLoadInfo& entry : loadsToProcess) {
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return GetModulesTrustPromise::CreateAndReject( return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -758,7 +803,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
moduleNtPathSet.PutEntry(entry.mNtLoadInfo.mSectionName.AsString()); moduleNtPathSet.PutEntry(entry.mNtLoadInfo.mSectionName.AsString());
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return GetModulesTrustPromise::CreateAndReject( return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -771,7 +816,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
ModulePaths moduleNtPaths(std::move(moduleNtPathSet)); ModulePaths moduleNtPaths(std::move(moduleNtPathSet));
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return GetModulesTrustPromise::CreateAndReject( return GetModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -787,7 +832,7 @@ UntrustedModulesProcessor::ProcessModuleLoadQueueChildProcess(
RefPtr<GetModulesTrustPromise::Private> p( RefPtr<GetModulesTrustPromise::Private> p(
new GetModulesTrustPromise::Private(__func__)); new GetModulesTrustPromise::Private(__func__));
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
p->Reject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); p->Reject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
return p; return p;
} }
@ -815,7 +860,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
MOZ_ASSERT(!XRE_IsParentProcess()); MOZ_ASSERT(!XRE_IsParentProcess());
AssertRunningOnLazyIdleThread(); AssertRunningOnLazyIdleThread();
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -837,7 +882,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
return; return;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -850,7 +895,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
if (!modules.IsEmpty()) { if (!modules.IsEmpty()) {
for (auto&& item : loads) { for (auto&& item : loads) {
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -860,7 +905,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -868,7 +913,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
std::move(item.mNtLoadInfo.mBacktrace); std::move(item.mNtLoadInfo.mBacktrace);
ProcessedModuleLoadEvent event(std::move(item), std::move(module)); ProcessedModuleLoadEvent event(std::move(item), std::move(module));
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -879,7 +924,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -890,7 +935,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -909,7 +954,7 @@ void UntrustedModulesProcessor::CompleteProcessing(
return; return;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return; return;
} }
@ -931,7 +976,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(XRE_IsParentProcess());
AssertRunningOnLazyIdleThread(); AssertRunningOnLazyIdleThread();
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return ModulesTrustPromise::CreateAndReject( return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -965,7 +1010,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
for (auto& resolvedNtPath : for (auto& resolvedNtPath :
aModPaths.mModuleNtPaths.as<ModulePaths::VecType>()) { aModPaths.mModuleNtPaths.as<ModulePaths::VecType>()) {
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return ModulesTrustPromise::CreateAndReject( return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -982,7 +1027,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return ModulesTrustPromise::CreateAndReject( return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }
@ -993,7 +1038,7 @@ RefPtr<ModulesTrustPromise> UntrustedModulesProcessor::GetModulesTrustInternal(
continue; continue;
} }
if (!mAllowProcessing) { if (!IsReadyForBackgroundProcessing()) {
return ModulesTrustPromise::CreateAndReject( return ModulesTrustPromise::CreateAndReject(
NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__); NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
} }

View File

@ -37,11 +37,16 @@ using GetModulesTrustIpcPromise =
class UntrustedModulesProcessor final : public nsIObserver { class UntrustedModulesProcessor final : public nsIObserver {
public: public:
static RefPtr<UntrustedModulesProcessor> Create(); static RefPtr<UntrustedModulesProcessor> Create(
bool aIsReadyForBackgroundProcessing);
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
// Called to check if the parent process is ready when a child process
// is spanwed
bool IsReadyForBackgroundProcessing() const;
// Called by DLL Services to explicitly begin shutting down // Called by DLL Services to explicitly begin shutting down
void Disable(); void Disable();
@ -65,7 +70,7 @@ class UntrustedModulesProcessor final : public nsIObserver {
private: private:
~UntrustedModulesProcessor() = default; ~UntrustedModulesProcessor() = default;
UntrustedModulesProcessor(); explicit UntrustedModulesProcessor(bool aIsReadyForBackgroundProcessing);
static bool IsSupportedProcessType(); static bool IsSupportedProcessType();
@ -141,8 +146,10 @@ class UntrustedModulesProcessor final : public nsIObserver {
// This member must only be touched on mThread // This member must only be touched on mThread
UntrustedModulesData mProcessedModuleLoads; UntrustedModulesData mProcessedModuleLoads;
enum class Status { StartingUp, Allowed, ShuttingDown };
// This member may be touched by any thread // This member may be touched by any thread
Atomic<bool> mAllowProcessing; Atomic<Status> mStatus;
// Cache all module records, including ones trusted and ones loaded in // Cache all module records, including ones trusted and ones loaded in
// child processes, in the browser process to avoid evaluating the same // child processes, in the browser process to avoid evaluating the same

View File

@ -59,10 +59,15 @@ DllServices* DllServices::Get() {
DllServices::~DllServices() { DisableFull(); } DllServices::~DllServices() { DisableFull(); }
void DllServices::StartUntrustedModulesProcessor() { void DllServices::StartUntrustedModulesProcessor(bool aIsStartingUp) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mUntrustedModulesProcessor); MOZ_ASSERT(!mUntrustedModulesProcessor);
mUntrustedModulesProcessor = UntrustedModulesProcessor::Create(); mUntrustedModulesProcessor = UntrustedModulesProcessor::Create(aIsStartingUp);
}
bool DllServices::IsReadyForBackgroundProcessing() const {
return mUntrustedModulesProcessor &&
mUntrustedModulesProcessor->IsReadyForBackgroundProcessing();
} }
RefPtr<UntrustedModulesPromise> DllServices::GetUntrustedModulesData() { RefPtr<UntrustedModulesPromise> DllServices::GetUntrustedModulesData() {

View File

@ -34,7 +34,8 @@ class DllServices final : public glue::DllServices {
static const char* kTopicDllLoadedMainThread; static const char* kTopicDllLoadedMainThread;
static const char* kTopicDllLoadedNonMainThread; static const char* kTopicDllLoadedNonMainThread;
void StartUntrustedModulesProcessor(); void StartUntrustedModulesProcessor(bool aIsReadyForBackgroundProcessing);
bool IsReadyForBackgroundProcessing() const;
RefPtr<UntrustedModulesPromise> GetUntrustedModulesData(); RefPtr<UntrustedModulesPromise> GetUntrustedModulesData();

View File

@ -353,7 +353,7 @@ BOOL CALLBACK UntrustedModulesFixture::InitialModuleLoadOnce(PINIT_ONCE, void*,
} }
RefPtr<DllServices> dllSvc(DllServices::Get()); RefPtr<DllServices> dllSvc(DllServices::Get());
dllSvc->StartUntrustedModulesProcessor(); dllSvc->StartUntrustedModulesProcessor(true);
for (int i = 0; i < kLoadCountAfterDllServices; ++i) { for (int i = 0; i < kLoadCountAfterDllServices; ++i) {
for (const auto& mod : kTestModules) { for (const auto& mod : kTestModules) {

View File

@ -5277,7 +5277,7 @@ nsresult XREMain::XRE_mainRun() {
#if defined(XP_WIN) #if defined(XP_WIN)
RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get()); RefPtr<mozilla::DllServices> dllServices(mozilla::DllServices::Get());
dllServices->StartUntrustedModulesProcessor(); dllServices->StartUntrustedModulesProcessor(false);
auto dllServicesDisable = auto dllServicesDisable =
MakeScopeExit([&dllServices]() { dllServices->DisableFull(); }); MakeScopeExit([&dllServices]() { dllServices->DisableFull(); });