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:
Daosheng Mu 2019-04-02 05:13:15 +00:00
parent 64fcb4fb58
commit 9904bad8e0
8 changed files with 98 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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