diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index 20868100e6..31ad17a386 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -180,12 +180,9 @@ protected void onStop() { @Override protected void onPause() { if (mIsPresentingImmersive) { - queueRunnable(new Runnable() { - @Override - public void run() { - exitImmersiveNative(); - } - }); + // This needs to be sync to ensure that WebVR is correctly paused. + // Also prevents a deadlock in onDestroy when the BrowserWidget is released. + exitImmersiveSync(); } mAudioEngine.pauseEngine(); SessionStore.get().setActive(false); @@ -217,8 +214,6 @@ protected void onDestroy() { SessionStore.get().clearListeners(); super.onDestroy(); - // FIXME: HACK TO KILL GECKO BETWEEN RUNS. - android.os.Process.killProcess(android.os.Process.myPid()); } @Override @@ -277,6 +272,26 @@ public void run() { } } + private void exitImmersiveSync() { + Runnable exitImmersive = new Runnable() { + @Override + public void run() { + exitImmersiveNative(); + synchronized(this) { + this.notifyAll(); + } + } + }; + synchronized (exitImmersive) { + queueRunnable(exitImmersive); + try { + exitImmersive.wait(); + } catch (InterruptedException e) { + Log.e(LOGTAG, "Waiting for exit immersive onPause interrupted"); + } + } + } + @Keep @SuppressWarnings("unused") void dispatchCreateWidget(final int aHandle, final SurfaceTexture aTexture, final int aWidth, final int aHeight) { diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index 43bfe4bff6..a63de37a9c 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -534,6 +534,9 @@ void BrowserWorld::ShutdownJava() { ASSERT_ON_RENDER_THREAD(); VRB_LOG("BrowserWorld::ShutdownJava"); + if (m.externalVR) { + m.externalVR->Shutdown(); + } GeckoSurfaceTexture::ShutdownJava(); VRBrowser::ShutdownJava(); if (m.env) { diff --git a/app/src/main/cpp/ExternalVR.cpp b/app/src/main/cpp/ExternalVR.cpp index 77c2f1d4f7..9f1b260e72 100644 --- a/app/src/main/cpp/ExternalVR.cpp +++ b/app/src/main/cpp/ExternalVR.cpp @@ -121,6 +121,7 @@ class Wait { namespace crow { struct ExternalVR::State { + static ExternalVR::State * sState; mozilla::gfx::VRExternalShmem data; mozilla::gfx::VRSystemState system; mozilla::gfx::VRBrowserState browser; @@ -132,16 +133,25 @@ struct ExternalVR::State { bool waitingForExit; State() : deviceCapabilities(0) { - memset(&data, 0, sizeof(mozilla::gfx::VRExternalShmem)); - memset(&system, 0, sizeof(mozilla::gfx::VRSystemState)); - memset(&browser, 0, sizeof(mozilla::gfx::VRBrowserState)); - data.version = mozilla::gfx::kVRExternalVersion; - data.size = sizeof(mozilla::gfx::VRExternalShmem); pthread_mutex_init(&data.systemMutex, nullptr); pthread_mutex_init(&data.browserMutex, nullptr); pthread_cond_init(&data.systemCond, nullptr); pthread_cond_init(&data.browserCond, nullptr); + } + + ~State() { + pthread_mutex_destroy(&(data.systemMutex)); + pthread_mutex_destroy(&(data.browserMutex)); + pthread_cond_destroy(&(data.systemCond)); + pthread_cond_destroy(&(data.browserCond)); + } + void Reset() { + memset(&data, 0, sizeof(mozilla::gfx::VRExternalShmem)); + memset(&system, 0, sizeof(mozilla::gfx::VRSystemState)); + memset(&browser, 0, sizeof(mozilla::gfx::VRBrowserState)); + data.version = mozilla::gfx::kVRExternalVersion; + data.size = sizeof(mozilla::gfx::VRExternalShmem); system.displayState.mIsConnected = true; system.displayState.mIsMounted = true; const vrb::Matrix identity = vrb::Matrix::Identity(); @@ -153,11 +163,12 @@ struct ExternalVR::State { waitingForExit = false; } - ~State() { - pthread_mutex_destroy(&(data.systemMutex)); - pthread_mutex_destroy(&(data.browserMutex)); - pthread_cond_destroy(&(data.systemCond)); - pthread_cond_destroy(&(data.browserCond)); + static ExternalVR::State& Instance() { + if (!sState) { + sState = new State(); + } + + return *sState; } void PullBrowserStateWhileLocked() { @@ -179,6 +190,8 @@ struct ExternalVR::State { } }; +ExternalVR::State * ExternalVR::State::sState = nullptr; + ExternalVRPtr ExternalVR::Create() { return std::make_shared >(); @@ -420,7 +433,16 @@ ExternalVR::StopPresenting() { m.waitingForExit = true; } -ExternalVR::ExternalVR(State& aState) : m(aState) { +void +ExternalVR::Shutdown() { + m.system.displayState.shutdown = true; + m.system.displayState.mSuppressFrames = true; + PushSystemState(); +} + + +ExternalVR::ExternalVR(State& aState) : m(State::Instance()) { + m.Reset(); PushSystemState(); } diff --git a/app/src/main/cpp/ExternalVR.h b/app/src/main/cpp/ExternalVR.h index d61568f655..05790c8352 100644 --- a/app/src/main/cpp/ExternalVR.h +++ b/app/src/main/cpp/ExternalVR.h @@ -40,6 +40,7 @@ class ExternalVR : public ImmersiveDisplay { const double aBottomDegrees) override; void SetEyeOffset(const device::Eye aEye, const float aX, const float aY, const float aZ) override; void SetEyeResolution(const int32_t aX, const int32_t aY) override; + void CompleteEnumeration() override; // ExternalVR interface void PushSystemState(); void PullBrowserState(); @@ -50,7 +51,7 @@ class ExternalVR : public ImmersiveDisplay { bool WaitFrameResult(); void GetFrameResult(int32_t& aSurfaceHandle, device::EyeRect& aLeftEye, device::EyeRect& aRightEye) const; void StopPresenting(); - void CompleteEnumeration() override; + void Shutdown(); protected: struct State; ExternalVR(State& aState);