Bug 1895215 - [devtools] Display cookie's partitionKey in storage panel. r=timhuang...
[gecko.git] / gfx / vr / ipc / VRProcessParent.cpp
blob01e4c610eea02bcc244986d5f0781aa3ab2c9693
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "VRProcessParent.h"
8 #include "VRGPUChild.h"
9 #include "VRProcessManager.h"
10 #include "mozilla/dom/ContentParent.h"
11 #include "mozilla/dom/MemoryReportRequest.h"
12 #include "mozilla/gfx/GPUProcessManager.h"
13 #include "mozilla/gfx/GPUChild.h"
14 #include "mozilla/ipc/Endpoint.h"
15 #include "mozilla/ipc/ProcessChild.h"
16 #include "mozilla/ipc/ProcessUtils.h"
17 #include "mozilla/ipc/ProtocolTypes.h"
18 #include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol
19 #include "mozilla/Preferences.h"
20 #include "mozilla/StaticPrefs_dom.h"
21 #include "mozilla/TimeStamp.h" // for TimeStamp
22 #include "mozilla/Unused.h"
23 #include "VRChild.h"
24 #include "VRThread.h"
26 #include "nsAppRunner.h" // for IToplevelProtocol
28 using std::string;
29 using std::vector;
31 using namespace mozilla::ipc;
33 namespace mozilla {
34 namespace gfx {
36 VRProcessParent::VRProcessParent(Listener* aListener)
37 : GeckoChildProcessHost(GeckoProcessType_VR),
38 mTaskFactory(this),
39 mListener(aListener),
40 mLaunchPhase(LaunchPhase::Unlaunched),
41 mChannelClosed(false),
42 mShutdownRequested(false) {}
44 VRProcessParent::~VRProcessParent() = default;
46 bool VRProcessParent::Launch() {
47 MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
48 MOZ_ASSERT(!mVRChild);
49 mLaunchThread = NS_GetCurrentThread();
51 mLaunchPhase = LaunchPhase::Waiting;
53 geckoargs::ChildProcessArgs extraArgs;
54 ProcessChild::AddPlatformBuildID(extraArgs);
56 mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
57 if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_VR,
58 /* remoteType */ ""_ns)) {
59 return false;
61 mPrefSerializer->AddSharedPrefCmdLineArgs(*this, extraArgs);
63 if (!GeckoChildProcessHost::AsyncLaunch(std::move(extraArgs))) {
64 mLaunchPhase = LaunchPhase::Complete;
65 mPrefSerializer = nullptr;
66 return false;
68 return true;
71 bool VRProcessParent::WaitForLaunch() {
72 if (mLaunchPhase == LaunchPhase::Complete) {
73 return !!mVRChild;
76 int32_t timeoutMs =
77 StaticPrefs::dom_vr_process_startup_timeout_ms_AtStartup();
79 // If one of the following environment variables are set we can effectively
80 // ignore the timeout - as we can guarantee the compositor process will be
81 // terminated
82 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
83 PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
84 timeoutMs = 0;
87 // Our caller expects the connection to be finished after we return, so we
88 // immediately set up the IPDL actor and fire callbacks. The IO thread will
89 // still dispatch a notification to the main thread - we'll just ignore it.
90 bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
91 result &= InitAfterConnect(result);
92 return result;
95 void VRProcessParent::Shutdown() {
96 MOZ_ASSERT(!mShutdownRequested);
97 mListener = nullptr;
99 if (mVRChild) {
100 // The channel might already be closed if we got here unexpectedly.
101 if (!mChannelClosed) {
102 mVRChild->Close();
104 // OnChannelClosed uses this to check if the shutdown was expected or
105 // unexpected.
106 mShutdownRequested = true;
108 #ifndef NS_FREE_PERMANENT_DATA
109 // No need to communicate shutdown, the VR process doesn't need to
110 // communicate anything back.
111 KillHard("NormalShutdown");
112 #endif
114 // If we're shutting down unexpectedly, we're in the middle of handling an
115 // ActorDestroy for PVRChild, which is still on the stack. We'll return
116 // back to OnChannelClosed.
118 // Otherwise, we'll wait for OnChannelClose to be called whenever PVRChild
119 // acknowledges shutdown.
120 return;
123 DestroyProcess();
126 void VRProcessParent::DestroyProcess() {
127 if (mLaunchThread) {
128 // Cancel all tasks. We don't want anything triggering after our caller
129 // expects this to go away.
131 MonitorAutoLock lock(mMonitor);
132 mTaskFactory.RevokeAll();
135 mLaunchThread->Dispatch(NS_NewRunnableFunction("DestroyProcessRunnable",
136 [this] { Destroy(); }));
140 bool VRProcessParent::InitAfterConnect(bool aSucceeded) {
141 MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
142 MOZ_ASSERT(!mVRChild);
144 mLaunchPhase = LaunchPhase::Complete;
145 mPrefSerializer = nullptr;
147 if (aSucceeded) {
148 GPUChild* gpuChild = GPUProcessManager::Get()->GetGPUChild();
149 if (!gpuChild) {
150 NS_WARNING(
151 "GPU process haven't connected with the parent process yet"
152 "when creating VR process.");
153 return false;
156 if (!StaticPrefs::dom_vr_enabled() &&
157 !StaticPrefs::dom_vr_webxr_enabled()) {
158 NS_WARNING("VR is not enabled when trying to create a VRChild");
159 return false;
162 mVRChild = MakeRefPtr<VRChild>(this);
164 DebugOnly<bool> rv = TakeInitialEndpoint().Bind(mVRChild.get());
165 MOZ_ASSERT(rv);
167 mVRChild->Init();
169 if (mListener) {
170 mListener->OnProcessLaunchComplete(this);
173 // Make vr-gpu process connection
174 Endpoint<PVRGPUChild> vrGPUBridge;
175 VRProcessManager* vpm = VRProcessManager::Get();
176 DebugOnly<bool> opened =
177 vpm->CreateGPUBridges(gpuChild->OtherEndpointProcInfo(), &vrGPUBridge);
178 MOZ_ASSERT(opened);
180 Unused << gpuChild->SendInitVR(std::move(vrGPUBridge));
183 return true;
186 void VRProcessParent::KillHard(const char* aReason) {
187 ProcessHandle handle = GetChildProcessHandle();
188 if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER)) {
189 NS_WARNING("failed to kill subprocess!");
192 SetAlreadyDead();
195 void VRProcessParent::OnChannelConnected(base::ProcessId peer_pid) {
196 MOZ_ASSERT(!NS_IsMainThread());
198 GeckoChildProcessHost::OnChannelConnected(peer_pid);
200 // Post a task to the main thread. Take the lock because mTaskFactory is not
201 // thread-safe.
202 RefPtr<Runnable> runnable;
204 MonitorAutoLock lock(mMonitor);
205 runnable = mTaskFactory.NewRunnableMethod(
206 &VRProcessParent::OnChannelConnectedTask);
208 NS_DispatchToMainThread(runnable);
211 void VRProcessParent::OnChannelConnectedTask() {
212 if (mLaunchPhase == LaunchPhase::Waiting) {
213 InitAfterConnect(true);
217 void VRProcessParent::OnChannelErrorTask() {
218 if (mLaunchPhase == LaunchPhase::Waiting) {
219 InitAfterConnect(false);
223 void VRProcessParent::OnChannelClosed() {
224 mChannelClosed = true;
225 if (!mShutdownRequested && mListener) {
226 // This is an unclean shutdown. Notify we're going away.
227 mListener->OnProcessUnexpectedShutdown(this);
228 } else {
229 DestroyProcess();
232 // Release the actor.
233 VRChild::Destroy(std::move(mVRChild));
234 MOZ_ASSERT(!mVRChild);
237 bool VRProcessParent::IsConnected() const { return !!mVRChild; }
239 } // namespace gfx
240 } // namespace mozilla