mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1155547, Part 2: Create PNuwa protocol (managed by PBackground) for forking content processes. r=khuey
This allows us to send a sync fork request to the Nuwa process when we need one but there is no spare process available. After an app is launched, the request to fork a spare process is still handled asynchronously. --HG-- extra : rebase_source : 9b692a647f4fc861285d95f0372d6a9913eadf64
This commit is contained in:
parent
bd05affa1b
commit
aa6f91dd67
@ -153,9 +153,9 @@
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include <setjmp.h>
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
#include "NuwaChild.h"
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
#include "mozilla/dom/GamepadService.h"
|
||||
@ -220,19 +220,6 @@ using namespace mozilla::system;
|
||||
#endif
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static bool sNuwaForking = false;
|
||||
|
||||
// The size of the reserved stack (in unsigned ints). It's used to reserve space
|
||||
// to push sigsetjmp() in NuwaCheckpointCurrentThread() to higher in the stack
|
||||
// so that after it returns and do other work we don't garble the stack we want
|
||||
// to preserve in NuwaCheckpointCurrentThread().
|
||||
#define RESERVED_INT_STACK 128
|
||||
|
||||
// A sentinel value for checking whether RESERVED_INT_STACK is large enough.
|
||||
#define STACK_SENTINEL_VALUE 0xdeadbeef
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -539,7 +526,7 @@ ContentChild* ContentChild::sSingleton;
|
||||
|
||||
// Performs initialization that is not fork-safe, i.e. that must be done after
|
||||
// forking from the Nuwa process.
|
||||
static void
|
||||
void
|
||||
InitOnContentProcessCreated()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
@ -2206,8 +2193,25 @@ ContentChild::RecvCycleCollect()
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static void
|
||||
OnFinishNuwaPreparation ()
|
||||
OnFinishNuwaPreparation()
|
||||
{
|
||||
// We want to ensure that the PBackground actor gets cloned in the Nuwa
|
||||
// process before we freeze. Also, we have to do this to avoid deadlock.
|
||||
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
|
||||
// main thread to wait for the IPC thread during the open operation.
|
||||
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
|
||||
// the Nuwa process is forked. Unless we ensure that the two cannot happen
|
||||
// at the same time then we risk deadlock. Spinning the event loop here
|
||||
// guarantees the ordering is safe for PBackground.
|
||||
while (!BackgroundChild::GetForCurrentThread()) {
|
||||
if (NS_WARN_IF(!NS_ProcessNextEvent())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This will create the actor.
|
||||
unused << mozilla::dom::NuwaChild::GetSingleton();
|
||||
|
||||
MakeNuwaProcess();
|
||||
}
|
||||
#endif
|
||||
@ -2493,87 +2497,6 @@ ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
class CallNuwaSpawn : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NuwaSpawn();
|
||||
if (IsNuwaProcess()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// In the new process.
|
||||
ContentChild* child = ContentChild::GetSingleton();
|
||||
child->SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
|
||||
|
||||
// Perform other after-fork initializations.
|
||||
InitOnContentProcessCreated();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
DoNuwaFork()
|
||||
{
|
||||
NuwaSpawnPrepare(); // NuwaSpawn will be blocked.
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> callSpawn(new CallNuwaSpawn());
|
||||
NS_DispatchToMainThread(callSpawn);
|
||||
}
|
||||
|
||||
// IOThread should be blocked here for waiting NuwaSpawn().
|
||||
NuwaSpawnWait(); // Now! NuwaSpawn can go.
|
||||
// Here, we can make sure the spawning was finished.
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should keep IO thread in a stable state and freeze it
|
||||
* until the spawning is finished.
|
||||
*/
|
||||
static void
|
||||
RunNuwaFork()
|
||||
{
|
||||
if (NuwaCheckpointCurrentThread()) {
|
||||
DoNuwaFork();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
ContentChild::RecvNuwaFork()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (sNuwaForking) { // No reentry.
|
||||
return true;
|
||||
}
|
||||
sNuwaForking = true;
|
||||
|
||||
// We want to ensure that the PBackground actor gets cloned in the Nuwa
|
||||
// process before we freeze. Also, we have to do this to avoid deadlock.
|
||||
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
|
||||
// main thread to wait for the IPC thread during the open operation.
|
||||
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
|
||||
// the Nuwa process is forked. Unless we ensure that the two cannot happen
|
||||
// at the same time then we risk deadlock. Spinning the event loop here
|
||||
// guarantees the ordering is safe for PBackground.
|
||||
while (!BackgroundChild::GetForCurrentThread()) {
|
||||
if (NS_WARN_IF(!NS_ProcessNextEvent())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MessageLoop* ioloop = XRE_GetIOMessageLoop();
|
||||
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
|
||||
return true;
|
||||
#else
|
||||
return false; // Makes the underlying IPC channel abort.
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvOnAppThemeChanged()
|
||||
{
|
||||
@ -2918,109 +2841,3 @@ ContentChild::RecvTestGraphicsDeviceReset(const uint32_t& aResetReason)
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if defined(MOZ_NUWA_PROCESS)
|
||||
NS_EXPORT void
|
||||
GetProtoFdInfos(NuwaProtoFdInfo* aInfoList,
|
||||
size_t aInfoListSize,
|
||||
size_t* aInfoSize)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
mozilla::dom::ContentChild* content =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
aInfoList[i].protoId = content->GetProtocolId();
|
||||
aInfoList[i].originFd =
|
||||
content->GetTransport()->GetFileDescriptor();
|
||||
i++;
|
||||
|
||||
IToplevelProtocol* actors[NUWA_TOPLEVEL_MAX];
|
||||
size_t count = content->GetOpenedActorsUnsafe(actors, ArrayLength(actors));
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
IToplevelProtocol* actor = actors[j];
|
||||
if (i >= aInfoListSize) {
|
||||
NS_RUNTIMEABORT("Too many top level protocols!");
|
||||
}
|
||||
|
||||
aInfoList[i].protoId = actor->GetProtocolId();
|
||||
aInfoList[i].originFd =
|
||||
actor->GetTransport()->GetFileDescriptor();
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i > NUWA_TOPLEVEL_MAX) {
|
||||
NS_RUNTIMEABORT("Too many top level protocols!");
|
||||
}
|
||||
*aInfoSize = i;
|
||||
}
|
||||
|
||||
class RunAddNewIPCProcess : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RunAddNewIPCProcess(pid_t aPid,
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping>& aMaps)
|
||||
: mPid(aPid)
|
||||
{
|
||||
mMaps.SwapElements(aMaps);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mozilla::dom::ContentChild::GetSingleton()->
|
||||
SendAddNewProcess(mPid, mMaps);
|
||||
|
||||
MOZ_ASSERT(sNuwaForking);
|
||||
sNuwaForking = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
pid_t mPid;
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping> mMaps;
|
||||
};
|
||||
|
||||
/**
|
||||
* AddNewIPCProcess() is called by Nuwa process to tell the parent
|
||||
* process that a new process is created.
|
||||
*
|
||||
* In the newly created process, ResetContentChildTransport() is called to
|
||||
* reset fd for the IPC Channel and the session.
|
||||
*/
|
||||
NS_EXPORT void
|
||||
AddNewIPCProcess(pid_t aPid, NuwaProtoFdInfo* aInfoList, size_t aInfoListSize)
|
||||
{
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping> maps;
|
||||
|
||||
for (size_t i = 0; i < aInfoListSize; i++) {
|
||||
int _fd = aInfoList[i].newFds[NUWA_NEWFD_PARENT];
|
||||
mozilla::ipc::FileDescriptor fd(_fd);
|
||||
mozilla::ipc::ProtocolFdMapping map(aInfoList[i].protoId, fd);
|
||||
maps.AppendElement(map);
|
||||
}
|
||||
|
||||
nsRefPtr<RunAddNewIPCProcess> runner = new RunAddNewIPCProcess(aPid, maps);
|
||||
NS_DispatchToMainThread(runner);
|
||||
}
|
||||
|
||||
NS_EXPORT void
|
||||
OnNuwaProcessReady()
|
||||
{
|
||||
mozilla::dom::ContentChild* content =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
content->SendNuwaReady();
|
||||
}
|
||||
|
||||
NS_EXPORT void
|
||||
AfterNuwaFork()
|
||||
{
|
||||
SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MOZ_NUWA_PROCESS
|
||||
|
||||
}
|
||||
|
@ -363,8 +363,6 @@ public:
|
||||
const bool& aIsHotSwappable) override;
|
||||
virtual bool RecvVolumeRemoved(const nsString& aFsName) override;
|
||||
|
||||
virtual bool RecvNuwaFork() override;
|
||||
|
||||
virtual bool
|
||||
RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override;
|
||||
virtual bool RecvMinimizeMemoryUsage() override;
|
||||
@ -517,6 +515,9 @@ private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
|
||||
};
|
||||
|
||||
void
|
||||
InitOnContentProcessCreated();
|
||||
|
||||
uint64_t
|
||||
NextWindowID();
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "mozilla/dom/ExternalHelperAppParent.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/GeolocationBinding.h"
|
||||
#include "mozilla/dom/NuwaParent.h"
|
||||
#include "mozilla/dom/PContentBridgeParent.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
|
||||
@ -75,6 +76,7 @@
|
||||
#include "mozilla/layers/SharedBufferManagerParent.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/media/MediaParent.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "mozilla/plugins/PluginBridge.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -2841,47 +2843,54 @@ ContentParent::RecvDataStoreGetStores(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvNuwaReady()
|
||||
void
|
||||
ContentParent::ForkNewProcess(bool aBlocking)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!IsNuwaProcess()) {
|
||||
NS_ERROR(
|
||||
nsPrintfCString(
|
||||
"Terminating child process %d for unauthorized IPC message: NuwaReady",
|
||||
Pid()).get());
|
||||
uint32_t pid;
|
||||
auto fds = MakeUnique<nsTArray<ProtocolFdMapping>>();
|
||||
|
||||
KillHard("NuwaReady");
|
||||
return false;
|
||||
MOZ_ASSERT(IsNuwaProcess() && mNuwaParent);
|
||||
|
||||
if (mNuwaParent->ForkNewProcess(pid, mozilla::Move(fds), aBlocking)) {
|
||||
OnNewProcessCreated(pid, mozilla::Move(fds));
|
||||
}
|
||||
sNuwaReady = true;
|
||||
PreallocatedProcessManager::OnNuwaReady();
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
|
||||
return false;
|
||||
NS_ERROR("ContentParent::ForkNewProcess() not implemented!");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
InfallibleTArray<ProtocolFdMapping>&& aFds)
|
||||
void
|
||||
ContentParent::OnNuwaReady()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!IsNuwaProcess()) {
|
||||
NS_ERROR(
|
||||
nsPrintfCString(
|
||||
"Terminating child process %d for unauthorized IPC message: "
|
||||
"AddNewProcess(%d)", Pid(), aPid).get());
|
||||
// Protection from unauthorized IPC message is done in PNuwa protocol.
|
||||
// Just assert that this actor is really for the Nuwa process.
|
||||
MOZ_ASSERT(IsNuwaProcess());
|
||||
|
||||
sNuwaReady = true;
|
||||
PreallocatedProcessManager::OnNuwaReady();
|
||||
return;
|
||||
#else
|
||||
NS_ERROR("ContentParent::OnNuwaReady() not implemented!");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::OnNewProcessCreated(uint32_t aPid,
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>>&& aFds)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Protection from unauthorized IPC message is done in PNuwa protocol.
|
||||
// Just assert that this actor is really for the Nuwa process.
|
||||
MOZ_ASSERT(IsNuwaProcess());
|
||||
|
||||
KillHard("AddNewProcess");
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<ContentParent> content;
|
||||
content = new ContentParent(this,
|
||||
MAGIC_PREALLOCATED_APP_MANIFEST_URL,
|
||||
aPid,
|
||||
Move(aFds));
|
||||
Move(*aFds.get()));
|
||||
content->Init();
|
||||
|
||||
size_t numNuwaPrefUpdates = sNuwaPrefUpdates ?
|
||||
@ -2909,10 +2918,10 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
"Unexpected values");
|
||||
|
||||
PreallocatedProcessManager::PublishSpareProcess(content);
|
||||
return true;
|
||||
return;
|
||||
#else
|
||||
NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!");
|
||||
return false;
|
||||
NS_ERROR("ContentParent::OnNewProcessCreated() not implemented!");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef mozilla_dom_ContentParent_h
|
||||
#define mozilla_dom_ContentParent_h
|
||||
|
||||
#include "mozilla/dom/NuwaParent.h"
|
||||
#include "mozilla/dom/PContentParent.h"
|
||||
#include "mozilla/dom/nsIContentParent.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
@ -383,6 +384,9 @@ public:
|
||||
|
||||
bool HasGamepadListener() const { return mHasGamepadListener; }
|
||||
|
||||
void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; }
|
||||
void ForkNewProcess(bool aBlocking);
|
||||
|
||||
protected:
|
||||
void OnChannelConnected(int32_t pid) override;
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
@ -775,10 +779,10 @@ private:
|
||||
|
||||
virtual bool RecvSystemMessageHandled() override;
|
||||
|
||||
virtual bool RecvNuwaReady() override;
|
||||
|
||||
virtual bool RecvAddNewProcess(const uint32_t& aPid,
|
||||
InfallibleTArray<ProtocolFdMapping>&& aFds) override;
|
||||
// Callbacks from NuwaParent.
|
||||
void OnNuwaReady();
|
||||
void OnNewProcessCreated(uint32_t aPid,
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>>&& aFds);
|
||||
|
||||
virtual bool RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) override;
|
||||
|
||||
@ -916,6 +920,9 @@ private:
|
||||
|
||||
friend class CrashReporterParent;
|
||||
|
||||
// Allows NuwaParent to access OnNuwaReady() and OnNewProcessCreated().
|
||||
friend class NuwaParent;
|
||||
|
||||
nsRefPtr<nsConsoleService> mConsoleService;
|
||||
nsConsoleService* GetConsoleService();
|
||||
|
||||
@ -933,6 +940,11 @@ private:
|
||||
#endif
|
||||
|
||||
PProcessHangMonitorParent* mHangMonitorActor;
|
||||
|
||||
// NuwaParent and ContentParent hold strong references to each other. The
|
||||
// cycle will be broken when either actor is destroyed.
|
||||
nsRefPtr<NuwaParent> mNuwaParent;
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
nsRefPtr<mozilla::ProfileGatherer> mGatherer;
|
||||
#endif
|
||||
|
256
dom/ipc/NuwaChild.cpp
Normal file
256
dom/ipc/NuwaChild.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
/* -*- 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 "ContentChild.h"
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
#if defined(XP_LINUX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#include "mozilla/SandboxInfo.h"
|
||||
#elif defined(XP_MACOSX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
#endif
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "NuwaChild.h"
|
||||
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
|
||||
namespace {
|
||||
|
||||
class CallNuwaSpawn: public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NuwaSpawn();
|
||||
if (IsNuwaProcess()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// In the new process.
|
||||
ContentChild* child = ContentChild::GetSingleton();
|
||||
child->InitProcessAttributes();
|
||||
|
||||
// Perform other after-fork initializations.
|
||||
InitOnContentProcessCreated();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
DoNuwaFork()
|
||||
{
|
||||
NuwaSpawnPrepare(); // NuwaSpawn will be blocked.
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> callSpawn(new CallNuwaSpawn());
|
||||
NS_DispatchToMainThread(callSpawn);
|
||||
}
|
||||
|
||||
// IOThread should be blocked here for waiting NuwaSpawn().
|
||||
NuwaSpawnWait(); // Now! NuwaSpawn can go.
|
||||
// Here, we can make sure the spawning was finished.
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should keep IO thread in a stable state and freeze it
|
||||
* until the spawning is finished.
|
||||
*/
|
||||
static void
|
||||
RunNuwaFork()
|
||||
{
|
||||
if (NuwaCheckpointCurrentThread()) {
|
||||
DoNuwaFork();
|
||||
}
|
||||
}
|
||||
|
||||
static bool sNuwaForking = false;
|
||||
|
||||
void
|
||||
NuwaFork()
|
||||
{
|
||||
if (sNuwaForking) { // No reentry.
|
||||
return;
|
||||
}
|
||||
sNuwaForking = true;
|
||||
|
||||
MessageLoop* ioloop = XRE_GetIOMessageLoop();
|
||||
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
|
||||
}
|
||||
|
||||
} // Anonymous namespace.
|
||||
|
||||
#endif
|
||||
|
||||
NuwaChild* NuwaChild::sSingleton;
|
||||
|
||||
NuwaChild*
|
||||
NuwaChild::GetSingleton()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSingleton) {
|
||||
PNuwaChild* nuwaChild =
|
||||
BackgroundChild::GetForCurrentThread()->SendPNuwaConstructor();
|
||||
MOZ_ASSERT(nuwaChild);
|
||||
|
||||
sSingleton = static_cast<NuwaChild*>(nuwaChild);
|
||||
}
|
||||
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NuwaChild::RecvFork()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!IsNuwaProcess()) {
|
||||
NS_ERROR(
|
||||
nsPrintfCString(
|
||||
"Terminating child process %d for unauthorized IPC message: "
|
||||
"RecvFork(%d)", getpid()).get());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableFunction(&NuwaFork);
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("NuwaChild::RecvFork() not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if defined(MOZ_NUWA_PROCESS)
|
||||
NS_EXPORT void
|
||||
GetProtoFdInfos(NuwaProtoFdInfo* aInfoList,
|
||||
size_t aInfoListSize,
|
||||
size_t* aInfoSize)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
mozilla::dom::ContentChild* content =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
aInfoList[i].protoId = content->GetProtocolId();
|
||||
aInfoList[i].originFd =
|
||||
content->GetTransport()->GetFileDescriptor();
|
||||
i++;
|
||||
|
||||
IToplevelProtocol* actors[NUWA_TOPLEVEL_MAX];
|
||||
size_t count = content->GetOpenedActorsUnsafe(actors, ArrayLength(actors));
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
IToplevelProtocol* actor = actors[j];
|
||||
if (i >= aInfoListSize) {
|
||||
NS_RUNTIMEABORT("Too many top level protocols!");
|
||||
}
|
||||
|
||||
aInfoList[i].protoId = actor->GetProtocolId();
|
||||
aInfoList[i].originFd =
|
||||
actor->GetTransport()->GetFileDescriptor();
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i > NUWA_TOPLEVEL_MAX) {
|
||||
NS_RUNTIMEABORT("Too many top level protocols!");
|
||||
}
|
||||
*aInfoSize = i;
|
||||
}
|
||||
|
||||
class RunAddNewIPCProcess : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RunAddNewIPCProcess(pid_t aPid,
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping>& aMaps)
|
||||
: mPid(aPid)
|
||||
{
|
||||
mMaps.SwapElements(aMaps);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NuwaChild::GetSingleton()->SendAddNewProcess(mPid, mMaps);
|
||||
|
||||
MOZ_ASSERT(sNuwaForking);
|
||||
sNuwaForking = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
pid_t mPid;
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping> mMaps;
|
||||
};
|
||||
|
||||
/**
|
||||
* AddNewIPCProcess() is called by Nuwa process to tell the parent
|
||||
* process that a new process is created.
|
||||
*
|
||||
* In the newly created process, ResetContentChildTransport() is called to
|
||||
* reset fd for the IPC Channel and the session.
|
||||
*/
|
||||
NS_EXPORT void
|
||||
AddNewIPCProcess(pid_t aPid, NuwaProtoFdInfo* aInfoList, size_t aInfoListSize)
|
||||
{
|
||||
nsTArray<mozilla::ipc::ProtocolFdMapping> maps;
|
||||
|
||||
for (size_t i = 0; i < aInfoListSize; i++) {
|
||||
int _fd = aInfoList[i].newFds[NUWA_NEWFD_PARENT];
|
||||
mozilla::ipc::FileDescriptor fd(_fd);
|
||||
mozilla::ipc::ProtocolFdMapping map(aInfoList[i].protoId, fd);
|
||||
maps.AppendElement(map);
|
||||
}
|
||||
|
||||
nsRefPtr<RunAddNewIPCProcess> runner = new RunAddNewIPCProcess(aPid, maps);
|
||||
NS_DispatchToMainThread(runner);
|
||||
}
|
||||
|
||||
NS_EXPORT void
|
||||
OnNuwaProcessReady()
|
||||
{
|
||||
NuwaChild* nuwaChild = NuwaChild::GetSingleton();
|
||||
MOZ_ASSERT(nuwaChild);
|
||||
|
||||
mozilla::unused << nuwaChild->SendNotifyReady();
|
||||
}
|
||||
|
||||
NS_EXPORT void
|
||||
AfterNuwaFork()
|
||||
{
|
||||
SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MOZ_NUWA_PROCESS
|
||||
|
||||
}
|
34
dom/ipc/NuwaChild.h
Normal file
34
dom/ipc/NuwaChild.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- 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_NuwaChild_h
|
||||
#define mozilla_dom_NuwaChild_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/PNuwaChild.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class NuwaChild: public mozilla::dom::PNuwaChild
|
||||
{
|
||||
public:
|
||||
virtual bool RecvFork() override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override
|
||||
{ }
|
||||
|
||||
static NuwaChild* GetSingleton();
|
||||
|
||||
private:
|
||||
static NuwaChild* sSingleton;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
263
dom/ipc/NuwaParent.cpp
Normal file
263
dom/ipc/NuwaParent.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
/* -*- 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 "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "NuwaParent.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::dom;
|
||||
using namespace IPC;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/*static*/ NuwaParent*
|
||||
NuwaParent::Alloc() {
|
||||
nsRefPtr<NuwaParent> actor = new NuwaParent();
|
||||
return actor.forget().take();
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
NuwaParent::ActorConstructed(mozilla::dom::PNuwaParent *aActor)
|
||||
{
|
||||
NuwaParent* actor = static_cast<NuwaParent*>(aActor);
|
||||
actor->ActorConstructed();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
NuwaParent::Dealloc(mozilla::dom::PNuwaParent *aActor)
|
||||
{
|
||||
nsRefPtr<NuwaParent> actor = dont_AddRef(static_cast<NuwaParent*>(aActor));
|
||||
return true;
|
||||
}
|
||||
|
||||
NuwaParent::NuwaParent()
|
||||
: mBlocked(false)
|
||||
, mMonitor("NuwaParent")
|
||||
, mClonedActor(nullptr)
|
||||
, mWorkerThread(do_GetCurrentThread())
|
||||
, mNewProcessPid(0)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
NuwaParent::~NuwaParent()
|
||||
{
|
||||
// Both the worker thread and the main thread (ContentParent) hold a ref to
|
||||
// this. The instance may be destroyed on either thread.
|
||||
MOZ_ASSERT(!mContentParent);
|
||||
}
|
||||
|
||||
inline void
|
||||
NuwaParent::AssertIsOnWorkerThread()
|
||||
{
|
||||
nsCOMPtr<nsIThread> currentThread = do_GetCurrentThread();
|
||||
MOZ_ASSERT(currentThread == mWorkerThread);
|
||||
}
|
||||
|
||||
bool
|
||||
NuwaParent::ActorConstructed()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(Manager());
|
||||
MOZ_ASSERT(!mContentParent);
|
||||
|
||||
mContentParent = BackgroundParent::GetContentParent(Manager());
|
||||
if (!mContentParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// mContentParent is guaranteed to be alive. It's safe to set its backward ref
|
||||
// to this.
|
||||
mContentParent->SetNuwaParent(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IProtocol*
|
||||
NuwaParent::CloneProtocol(Channel* aChannel,
|
||||
ProtocolCloneContext* aCtx)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsRefPtr<NuwaParent> self = this;
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
// Alloc NuwaParent on the worker thread.
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([self] () -> void
|
||||
{
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
// XXX Calling NuwaParent::Alloc() leads to a compilation error. Use
|
||||
// self->Alloc() as a workaround.
|
||||
self->mClonedActor = self->Alloc();
|
||||
lock.Notify();
|
||||
});
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mWorkerThread->Dispatch(runnable,
|
||||
NS_DISPATCH_NORMAL)));
|
||||
|
||||
while (!mClonedActor) {
|
||||
lock.Wait();
|
||||
}
|
||||
nsRefPtr<NuwaParent> actor = mClonedActor;
|
||||
mClonedActor = nullptr;
|
||||
|
||||
// mManager of the cloned actor is assigned after returning from this method.
|
||||
// We can't call ActorConstructed() right after Alloc() in the above runnable.
|
||||
// To be safe we dispatch a runnable to the current thread to do it.
|
||||
runnable = NS_NewRunnableFunction([actor] () -> void
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIRunnable> nested = NS_NewRunnableFunction([actor] () -> void
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// Call NuwaParent::ActorConstructed() on the worker thread.
|
||||
actor->ActorConstructed();
|
||||
|
||||
// The actor can finally be deleted after fully constructed.
|
||||
mozilla::unused << actor->Send__delete__(actor);
|
||||
});
|
||||
MOZ_ASSERT(nested);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
actor->mWorkerThread->Dispatch(nested, NS_DISPATCH_NORMAL)));
|
||||
});
|
||||
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
void
|
||||
NuwaParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<NuwaParent> self = this;
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([self] () -> void
|
||||
{
|
||||
// These extra nsRefPtr serve as kungFuDeathGrip to keep both objects from
|
||||
// deletion in breaking the ref cycle.
|
||||
nsRefPtr<ContentParent> contentParent = self->mContentParent;
|
||||
|
||||
contentParent->SetNuwaParent(nullptr);
|
||||
// Need to clear the ref to ContentParent on the main thread.
|
||||
self->mContentParent = nullptr;
|
||||
});
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
|
||||
bool
|
||||
NuwaParent::RecvNotifyReady()
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!mContentParent || !mContentParent->IsNuwaProcess()) {
|
||||
NS_ERROR("Received NotifyReady() message from a non-Nuwa process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Creating a NonOwningRunnableMethod here is safe because refcount changes of
|
||||
// mContentParent have to go the the main thread. The mContentParent will
|
||||
// be alive when the runnable runs.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewNonOwningRunnableMethod(mContentParent.get(),
|
||||
&ContentParent::OnNuwaReady);
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("NuwaParent::RecvNotifyReady() not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
NuwaParent::RecvAddNewProcess(const uint32_t& aPid,
|
||||
nsTArray<ProtocolFdMapping>&& aFds)
|
||||
{
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (!mContentParent || !mContentParent->IsNuwaProcess()) {
|
||||
NS_ERROR("Received AddNewProcess() message from a non-Nuwa process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mNewProcessPid = aPid;
|
||||
mNewProcessFds->SwapElements(aFds);
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mBlocked) {
|
||||
// Unblock ForkNewProcess().
|
||||
mMonitor.Notify();
|
||||
mBlocked = false;
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewNonOwningRunnableMethodWithArgs<
|
||||
uint32_t,
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>>&& >(
|
||||
mContentParent.get(),
|
||||
&ContentParent::OnNewProcessCreated,
|
||||
mNewProcessPid,
|
||||
Move(mNewProcessFds));
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
NS_ERROR("NuwaParent::RecvAddNewProcess() not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
NuwaParent::ForkNewProcess(uint32_t& aPid,
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>>&& aFds,
|
||||
bool aBlocking)
|
||||
{
|
||||
MOZ_ASSERT(mWorkerThread);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mNewProcessFds = Move(aFds);
|
||||
|
||||
nsRefPtr<NuwaParent> self = this;
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([self] () -> void
|
||||
{
|
||||
mozilla::unused << self->SendFork();
|
||||
});
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mWorkerThread->Dispatch(runnable,
|
||||
NS_DISPATCH_NORMAL)));
|
||||
if (!aBlocking) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mBlocked = true;
|
||||
while (mBlocked) {
|
||||
// This will be notified in NuwaParent::RecvAddNewProcess().
|
||||
lock.Wait();
|
||||
}
|
||||
|
||||
if (!mNewProcessPid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aPid = mNewProcessPid;
|
||||
aFds = Move(mNewProcessFds);
|
||||
|
||||
mNewProcessPid = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
73
dom/ipc/NuwaParent.h
Normal file
73
dom/ipc/NuwaParent.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* -*- 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_NuwaParent_h
|
||||
#define mozilla_dom_NuwaParent_h
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "mozilla/dom/PNuwaParent.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ContentParent;
|
||||
|
||||
class NuwaParent : public mozilla::dom::PNuwaParent
|
||||
{
|
||||
public:
|
||||
explicit NuwaParent();
|
||||
|
||||
// Called on the main thread.
|
||||
bool ForkNewProcess(uint32_t& aPid,
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>>&& aFds,
|
||||
bool aBlocking);
|
||||
|
||||
// Called on the background thread.
|
||||
bool ActorConstructed();
|
||||
|
||||
// Both the worker thread and the main thread hold a ref to this.
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NuwaParent)
|
||||
|
||||
// Functions to be invoked by the manager of this actor to alloc/dealloc the
|
||||
// actor.
|
||||
static NuwaParent* Alloc();
|
||||
static bool ActorConstructed(mozilla::dom::PNuwaParent *aActor);
|
||||
static bool Dealloc(mozilla::dom::PNuwaParent *aActor);
|
||||
|
||||
protected:
|
||||
virtual ~NuwaParent();
|
||||
|
||||
virtual bool RecvNotifyReady() override;
|
||||
virtual bool RecvAddNewProcess(const uint32_t& aPid,
|
||||
nsTArray<ProtocolFdMapping>&& aFds) override;
|
||||
virtual mozilla::ipc::IProtocol*
|
||||
CloneProtocol(Channel* aChannel,
|
||||
ProtocolCloneContext* aCtx) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
private:
|
||||
void AssertIsOnWorkerThread();
|
||||
|
||||
bool mBlocked;
|
||||
mozilla::Monitor mMonitor;
|
||||
NuwaParent* mClonedActor;
|
||||
|
||||
nsCOMPtr<nsIThread> mWorkerThread;
|
||||
|
||||
uint32_t mNewProcessPid;
|
||||
UniquePtr<nsTArray<ProtocolFdMapping>> mNewProcessFds;
|
||||
|
||||
// The mutual reference will be broken on the main thread.
|
||||
nsRefPtr<ContentParent> mContentParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -579,9 +579,6 @@ child:
|
||||
// Notify volume is removed.
|
||||
VolumeRemoved(nsString fsName);
|
||||
|
||||
// Ask the Nuwa process to create a new child process.
|
||||
NuwaFork();
|
||||
|
||||
NotifyProcessPriorityChanged(ProcessPriority priority);
|
||||
MinimizeMemoryUsage();
|
||||
|
||||
@ -888,10 +885,6 @@ parent:
|
||||
// Notify the parent that the child has finished handling a system message.
|
||||
async SystemMessageHandled();
|
||||
|
||||
NuwaReady();
|
||||
|
||||
sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);
|
||||
|
||||
// called by the child (test code only) to propagate volume changes to the parent
|
||||
async CreateFakeVolume(nsString fsName, nsString mountPoint);
|
||||
async SetFakeVolumeState(nsString fsName, int32_t fsState);
|
||||
|
31
dom/ipc/PNuwa.ipdl
Normal file
31
dom/ipc/PNuwa.ipdl
Normal file
@ -0,0 +1,31 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 protocol PBackground;
|
||||
include ProtocolTypes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
sync protocol PNuwa
|
||||
{
|
||||
manager PBackground;
|
||||
|
||||
child:
|
||||
// Ask the Nuwa process to create a new child process.
|
||||
async Fork();
|
||||
|
||||
// This message will be sent to non-Nuwa process, or to Nuwa process during
|
||||
// test.
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async NotifyReady();
|
||||
sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);
|
||||
};
|
||||
|
||||
} // namespace layout
|
||||
} // namespace mozilla
|
||||
|
@ -278,10 +278,15 @@ PreallocatedProcessManagerImpl::GetSpareProcess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mSpareProcesses.IsEmpty()) {
|
||||
if (!mIsNuwaReady) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (mSpareProcesses.IsEmpty()) {
|
||||
// After this call, there should be a spare process.
|
||||
mPreallocatedAppProcess->ForkNewProcess(true);
|
||||
}
|
||||
|
||||
nsRefPtr<ContentParent> process = mSpareProcesses.LastElement();
|
||||
mSpareProcesses.RemoveElementAt(mSpareProcesses.Length() - 1);
|
||||
|
||||
@ -369,7 +374,7 @@ PreallocatedProcessManagerImpl::PreallocatedProcessReady()
|
||||
void
|
||||
PreallocatedProcessManagerImpl::NuwaFork()
|
||||
{
|
||||
mozilla::unused << mPreallocatedAppProcess->SendNuwaFork();
|
||||
mPreallocatedAppProcess->ForkNewProcess(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -34,6 +34,8 @@ EXPORTS.mozilla.dom += [
|
||||
'FilePickerParent.h',
|
||||
'nsIContentChild.h',
|
||||
'nsIContentParent.h',
|
||||
'NuwaChild.h',
|
||||
'NuwaParent.h',
|
||||
'PermissionMessageUtils.h',
|
||||
'StructuredCloneUtils.h',
|
||||
'TabChild.h',
|
||||
@ -62,6 +64,8 @@ UNIFIED_SOURCES += [
|
||||
'FilePickerParent.cpp',
|
||||
'nsIContentChild.cpp',
|
||||
'nsIContentParent.cpp',
|
||||
'NuwaChild.cpp',
|
||||
'NuwaParent.cpp',
|
||||
'PermissionMessageUtils.cpp',
|
||||
'PreallocatedProcessManager.cpp',
|
||||
'ProcessPriorityManager.cpp',
|
||||
@ -101,6 +105,7 @@ IPDL_SOURCES += [
|
||||
'PDocumentRenderer.ipdl',
|
||||
'PFilePicker.ipdl',
|
||||
'PMemoryReportRequest.ipdl',
|
||||
'PNuwa.ipdl',
|
||||
'PPluginWidget.ipdl',
|
||||
'PProcessHangMonitor.ipdl',
|
||||
'PScreenManager.ipdl',
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/MessagePortChild.h"
|
||||
#include "mozilla/dom/NuwaChild.h"
|
||||
#include "mozilla/ipc/PBackgroundTestChild.h"
|
||||
#include "mozilla/layout/VsyncChild.h"
|
||||
#include "mozilla/net/PUDPSocketChild.h"
|
||||
@ -57,6 +58,7 @@ using mozilla::net::PUDPSocketChild;
|
||||
using mozilla::dom::cache::PCacheChild;
|
||||
using mozilla::dom::cache::PCacheStorageChild;
|
||||
using mozilla::dom::cache::PCacheStreamControlChild;
|
||||
using mozilla::dom::PNuwaChild;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BackgroundChildImpl::ThreadLocal
|
||||
@ -350,6 +352,21 @@ BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor)
|
||||
return true;
|
||||
}
|
||||
|
||||
PNuwaChild*
|
||||
BackgroundChildImpl::AllocPNuwaChild()
|
||||
{
|
||||
return new mozilla::dom::NuwaChild();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundChildImpl::DeallocPNuwaChild(PNuwaChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -122,6 +122,12 @@ protected:
|
||||
|
||||
virtual bool
|
||||
DeallocPMessagePortChild(PMessagePortChild* aActor) override;
|
||||
|
||||
virtual PNuwaChild*
|
||||
AllocPNuwaChild() override;
|
||||
|
||||
virtual bool
|
||||
DeallocPNuwaChild(PNuwaChild* aActor) override;
|
||||
};
|
||||
|
||||
class BackgroundChildImpl::ThreadLocal final
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/NuwaParent.h"
|
||||
#include "mozilla/dom/PBlobParent.h"
|
||||
#include "mozilla/dom/MessagePortParent.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
@ -42,6 +43,8 @@ using mozilla::dom::cache::PCacheStorageParent;
|
||||
using mozilla::dom::cache::PCacheStreamControlParent;
|
||||
using mozilla::dom::MessagePortParent;
|
||||
using mozilla::dom::PMessagePortParent;
|
||||
using mozilla::dom::PNuwaParent;
|
||||
using mozilla::dom::NuwaParent;
|
||||
using mozilla::dom::UDPSocketParent;
|
||||
|
||||
namespace {
|
||||
@ -233,6 +236,24 @@ BackgroundParentImpl::DeallocPFileDescriptorSetParent(
|
||||
return true;
|
||||
}
|
||||
|
||||
PNuwaParent*
|
||||
BackgroundParentImpl::AllocPNuwaParent()
|
||||
{
|
||||
return mozilla::dom::NuwaParent::Alloc();
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::RecvPNuwaConstructor(PNuwaParent* aActor)
|
||||
{
|
||||
return mozilla::dom::NuwaParent::ActorConstructed(aActor);
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundParentImpl::DeallocPNuwaParent(PNuwaParent *aActor)
|
||||
{
|
||||
return mozilla::dom::NuwaParent::Dealloc(aActor);
|
||||
}
|
||||
|
||||
BackgroundParentImpl::PVsyncParent*
|
||||
BackgroundParentImpl::AllocPVsyncParent()
|
||||
{
|
||||
|
@ -86,6 +86,15 @@ protected:
|
||||
virtual bool
|
||||
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
|
||||
|
||||
virtual PNuwaParent*
|
||||
AllocPNuwaParent() override;
|
||||
|
||||
virtual bool
|
||||
RecvPNuwaConstructor(PNuwaParent* aActor) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPNuwaParent(PNuwaParent* aActor) override;
|
||||
|
||||
virtual PServiceWorkerManagerParent*
|
||||
AllocPServiceWorkerManagerParent() override;
|
||||
|
||||
|
@ -13,8 +13,9 @@
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/PNuwa.h"
|
||||
#include "mozilla/hal_sandbox/PHal.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
@ -176,8 +177,8 @@ ProcessLink::SendMessage(Message *msg)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
|
||||
switch (msg->type()) {
|
||||
case mozilla::dom::PContent::Msg_NuwaFork__ID:
|
||||
case mozilla::dom::PContent::Reply_AddNewProcess__ID:
|
||||
case mozilla::dom::PNuwa::Msg_Fork__ID:
|
||||
case mozilla::dom::PNuwa::Reply_AddNewProcess__ID:
|
||||
case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
|
||||
case mozilla::hal_sandbox::PHal::Msg_NotifyNetworkChange__ID:
|
||||
case GOODBYE_MESSAGE_TYPE:
|
||||
|
@ -11,6 +11,7 @@ include protocol PCacheStorage;
|
||||
include protocol PCacheStreamControl;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PMessagePort;
|
||||
include protocol PNuwa;
|
||||
include protocol PServiceWorkerManager;
|
||||
include protocol PUDPSocket;
|
||||
include protocol PVsync;
|
||||
@ -36,6 +37,7 @@ sync protocol PBackground
|
||||
manages PCacheStreamControl;
|
||||
manages PFileDescriptorSet;
|
||||
manages PMessagePort;
|
||||
manages PNuwa;
|
||||
manages PServiceWorkerManager;
|
||||
manages PUDPSocket;
|
||||
manages PVsync;
|
||||
@ -60,6 +62,8 @@ parent:
|
||||
|
||||
PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
|
||||
|
||||
PNuwa();
|
||||
|
||||
MessagePortForceClose(nsID uuid, nsID destinationUuid, uint32_t sequenceId);
|
||||
|
||||
child:
|
||||
|
Loading…
Reference in New Issue
Block a user