зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1520339 - Part 1: adding ensure VR process ready mechanism. r=kip
Differential Revision: https://phabricator.services.mozilla.com/D25320 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
64fcb4fb58
Коммит
9904bad8e0
|
@ -403,6 +403,7 @@ class gfxPrefs final {
|
|||
DECL_GFX_PREF(Live, "dom.vr.puppet.submitframe", VRPuppetSubmitFrame, uint32_t, 0);
|
||||
DECL_GFX_PREF(Live, "dom.vr.display.rafMaxDuration", VRDisplayRafMaxDuration, uint32_t, 50);
|
||||
DECL_GFX_PREF(Once, "dom.vr.process.enabled", VRProcessEnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "dom.vr.process.startup_timeout_ms", VRProcessTimeoutMs, int32_t, 5000);
|
||||
DECL_GFX_PREF(Once, "dom.vr.service.enabled", VRServiceEnabled, bool, true);
|
||||
DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false);
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ parent:
|
|||
async OpenVRControllerManifestPathToVR(OpenVRControllerType aType, nsCString aPath);
|
||||
|
||||
child:
|
||||
// Sent when the GPU process has initialized devices. This occurs once, after
|
||||
// Init().
|
||||
async InitComplete();
|
||||
async OpenVRControllerActionPathToParent(nsCString aPath);
|
||||
async OpenVRControllerManifestPathToParent(OpenVRControllerType aType, nsCString aPath);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
|
||||
|
|
|
@ -30,6 +30,7 @@ class VRChild final : public PVRChild, public gfxVarReceiver {
|
|||
|
||||
static void Destroy(UniquePtr<VRChild>&& aChild);
|
||||
void Init();
|
||||
bool EnsureVRReady();
|
||||
virtual void OnVarChanged(const GfxVarUpdate& aVar) override;
|
||||
|
||||
protected:
|
||||
|
@ -38,12 +39,14 @@ class VRChild final : public PVRChild, public gfxVarReceiver {
|
|||
const nsCString& aPath);
|
||||
mozilla::ipc::IPCResult RecvOpenVRControllerManifestPathToParent(
|
||||
const OpenVRControllerType& aType, const nsCString& aPath);
|
||||
mozilla::ipc::IPCResult RecvInitComplete();
|
||||
mozilla::ipc::IPCResult RecvInitCrashReporter(
|
||||
Shmem&& shmem, const NativeThreadId& aThreadId);
|
||||
|
||||
private:
|
||||
VRProcessParent* mHost;
|
||||
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
|
||||
bool mVRReady;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -39,6 +39,8 @@ IPCResult VRParent::RecvNewGPUVRManager(Endpoint<PVRGPUParent>&& aEndpoint) {
|
|||
IPCResult VRParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
|
||||
nsTArray<GfxVarUpdate>&& vars,
|
||||
const DevicePrefs& devicePrefs) {
|
||||
Unused << SendInitComplete();
|
||||
|
||||
const nsTArray<gfxPrefs::Pref*>& globalPrefs = gfxPrefs::all();
|
||||
for (auto& setting : prefs) {
|
||||
gfxPrefs::Pref* pref = globalPrefs[setting.index()];
|
||||
|
@ -161,6 +163,7 @@ bool VRParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
|
|||
return false;
|
||||
}
|
||||
|
||||
mozilla::ipc::SetThisProcessName("VR Process");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ void VRProcessManager::Initialize() {
|
|||
/* static */
|
||||
void VRProcessManager::Shutdown() { sSingleton = nullptr; }
|
||||
|
||||
VRProcessManager::VRProcessManager() : mProcess(nullptr) {
|
||||
VRProcessManager::VRProcessManager() : mProcess(nullptr), mVRChild(nullptr) {
|
||||
MOZ_COUNT_CTOR(VRProcessManager);
|
||||
|
||||
mObserver = new Observer(this);
|
||||
|
@ -79,14 +79,43 @@ void VRProcessManager::DestroyProcess() {
|
|||
|
||||
mProcess->Shutdown();
|
||||
mProcess = nullptr;
|
||||
mVRChild = nullptr;
|
||||
|
||||
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::VRProcessStatus,
|
||||
NS_LITERAL_CSTRING("Destroyed"));
|
||||
}
|
||||
|
||||
bool VRProcessManager::EnsureVRReady() {
|
||||
if (mProcess && !mProcess->IsConnected()) {
|
||||
if (!mProcess->WaitForLaunch()) {
|
||||
// If this fails, we should have fired OnProcessLaunchComplete and
|
||||
// removed the process.
|
||||
MOZ_ASSERT(!mProcess && !mVRChild);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mVRChild) {
|
||||
if (mVRChild->EnsureVRReady()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the initialization above fails, we likely have a GPU process teardown
|
||||
// waiting in our message queue (or will soon). We need to ensure we don't
|
||||
// restart it later because if we fail here, our callers assume they should
|
||||
// fall back to a combined UI/GPU process. This also ensures our internal
|
||||
// state is consistent (e.g. process token is reset).
|
||||
DisableVRProcess("Failed to initialize VR process");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VRProcessManager::OnProcessLaunchComplete(VRProcessParent* aParent) {
|
||||
MOZ_ASSERT(mProcess && mProcess == aParent);
|
||||
|
||||
mVRChild = mProcess->GetActor();
|
||||
|
||||
if (!mProcess->IsConnected()) {
|
||||
DestroyProcess();
|
||||
return;
|
||||
|
|
|
@ -27,6 +27,12 @@ class VRProcessManager final : public VRProcessParent::Listener {
|
|||
|
||||
// If not using a VR process, launch a new VR process asynchronously.
|
||||
void LaunchVRProcess();
|
||||
|
||||
// Ensure that VR-bound methods can be used. If no VR process is being
|
||||
// used, or one is launched and ready, this function returns immediately.
|
||||
// Otherwise it blocks until the VR process has finished launching.
|
||||
bool EnsureVRReady();
|
||||
|
||||
bool CreateGPUBridges(base::ProcessId aOtherProcess,
|
||||
mozilla::ipc::Endpoint<PVRGPUChild>* aOutVRBridge);
|
||||
|
||||
|
@ -65,6 +71,7 @@ class VRProcessManager final : public VRProcessParent::Listener {
|
|||
|
||||
RefPtr<Observer> mObserver;
|
||||
VRProcessParent* mProcess;
|
||||
VRChild* mVRChild;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -33,6 +33,7 @@ VRProcessParent::VRProcessParent(Listener* aListener)
|
|||
: GeckoChildProcessHost(GeckoProcessType_VR),
|
||||
mTaskFactory(this),
|
||||
mListener(aListener),
|
||||
mLaunchPhase(LaunchPhase::Unlaunched),
|
||||
mChannelClosed(false),
|
||||
mShutdownRequested(false) {
|
||||
MOZ_COUNT_CTOR(VRProcessParent);
|
||||
|
@ -49,19 +50,47 @@ VRProcessParent::~VRProcessParent() {
|
|||
}
|
||||
|
||||
bool VRProcessParent::Launch() {
|
||||
MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
|
||||
MOZ_ASSERT(!mVRChild);
|
||||
mLaunchThread = NS_GetCurrentThread();
|
||||
|
||||
mLaunchPhase = LaunchPhase::Waiting;
|
||||
|
||||
std::vector<std::string> extraArgs;
|
||||
nsCString parentBuildID(mozilla::PlatformBuildID());
|
||||
extraArgs.push_back("-parentBuildID");
|
||||
extraArgs.push_back(parentBuildID.get());
|
||||
|
||||
if (!GeckoChildProcessHost::AsyncLaunch(extraArgs)) {
|
||||
mLaunchPhase = LaunchPhase::Complete;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VRProcessParent::WaitForLaunch() {
|
||||
if (mLaunchPhase == LaunchPhase::Complete) {
|
||||
return !!mVRChild;
|
||||
}
|
||||
|
||||
int32_t timeoutMs = gfxPrefs::VRProcessTimeoutMs();
|
||||
|
||||
// If one of the following environment variables are set we can effectively
|
||||
// ignore the timeout - as we can guarantee the compositor process will be
|
||||
// terminated
|
||||
if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
|
||||
PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
|
||||
timeoutMs = 0;
|
||||
}
|
||||
|
||||
// Our caller expects the connection to be finished after we return, so we
|
||||
// immediately set up the IPDL actor and fire callbacks. The IO thread will
|
||||
// still dispatch a notification to the main thread - we'll just ignore it.
|
||||
bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
|
||||
InitAfterConnect(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void VRProcessParent::Shutdown() {
|
||||
MOZ_ASSERT(!mShutdownRequested);
|
||||
mListener = nullptr;
|
||||
|
@ -101,6 +130,10 @@ void VRProcessParent::DestroyProcess() {
|
|||
}
|
||||
|
||||
void VRProcessParent::InitAfterConnect(bool aSucceeded) {
|
||||
MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
|
||||
MOZ_ASSERT(!mVRChild);
|
||||
|
||||
mLaunchPhase = LaunchPhase::Complete;
|
||||
if (aSucceeded) {
|
||||
mVRChild = MakeUnique<VRChild>(this);
|
||||
|
||||
|
@ -157,10 +190,16 @@ void VRProcessParent::OnChannelConnected(int32_t peer_pid) {
|
|||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
void VRProcessParent::OnChannelConnectedTask() { InitAfterConnect(true); }
|
||||
void VRProcessParent::OnChannelConnectedTask() {
|
||||
if (mLaunchPhase == LaunchPhase::Waiting) {
|
||||
InitAfterConnect(true);
|
||||
}
|
||||
}
|
||||
|
||||
void VRProcessParent::OnChannelErrorTask() {
|
||||
MOZ_ASSERT(false, "VR process channel error.");
|
||||
if (mLaunchPhase == LaunchPhase::Waiting) {
|
||||
InitAfterConnect(false);
|
||||
}
|
||||
}
|
||||
|
||||
void VRProcessParent::OnChannelClosed() {
|
||||
|
|
|
@ -32,6 +32,11 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost {
|
|||
explicit VRProcessParent(Listener* aListener);
|
||||
|
||||
bool Launch();
|
||||
// If the process is being launched, block until it has launched and
|
||||
// connected. If a launch task is pending, it will fire immediately.
|
||||
//
|
||||
// Returns true if the process is successfully connected; false otherwise.
|
||||
bool WaitForLaunch();
|
||||
void Shutdown();
|
||||
void DestroyProcess();
|
||||
bool CanShutdown() override { return true; }
|
||||
|
@ -45,6 +50,9 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost {
|
|||
|
||||
base::ProcessId OtherPid();
|
||||
VRChild* GetActor() const { return mVRChild.get(); }
|
||||
// Return a unique id for this process, guaranteed not to be shared with any
|
||||
// past or future instance of VRProcessParent.
|
||||
uint64_t GetProcessToken() const;
|
||||
|
||||
private:
|
||||
~VRProcessParent();
|
||||
|
@ -59,6 +67,8 @@ class VRProcessParent final : public mozilla::ipc::GeckoChildProcessHost {
|
|||
nsCOMPtr<nsIThread> mLaunchThread;
|
||||
Listener* mListener;
|
||||
|
||||
enum class LaunchPhase { Unlaunched, Waiting, Complete };
|
||||
LaunchPhase mLaunchPhase;
|
||||
bool mChannelClosed;
|
||||
bool mShutdownRequested;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче