tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

VRProcessParent.cpp (7000B)


      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/. */
      6 
      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 "VRChild.h"
     23 #include "VRThread.h"
     24 
     25 #include "nsAppRunner.h"  // for IToplevelProtocol
     26 
     27 using std::string;
     28 using std::vector;
     29 
     30 using namespace mozilla::ipc;
     31 
     32 namespace mozilla {
     33 namespace gfx {
     34 
     35 VRProcessParent::VRProcessParent(Listener* aListener)
     36    : GeckoChildProcessHost(GeckoProcessType_VR),
     37      mTaskFactory(this),
     38      mListener(aListener),
     39      mLaunchPhase(LaunchPhase::Unlaunched),
     40      mChannelClosed(false),
     41      mShutdownRequested(false) {}
     42 
     43 VRProcessParent::~VRProcessParent() = default;
     44 
     45 bool VRProcessParent::Launch() {
     46  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched);
     47  MOZ_ASSERT(!mVRChild);
     48  mLaunchThread = NS_GetCurrentThread();
     49 
     50  mLaunchPhase = LaunchPhase::Waiting;
     51 
     52  geckoargs::ChildProcessArgs extraArgs;
     53  ProcessChild::AddPlatformBuildID(extraArgs);
     54 
     55  mPrefSerializer = MakeUnique<ipc::SharedPreferenceSerializer>();
     56  if (!mPrefSerializer->SerializeToSharedMemory(GeckoProcessType_VR,
     57                                                /* remoteType */ ""_ns)) {
     58    return false;
     59  }
     60  mPrefSerializer->AddSharedPrefCmdLineArgs(*this, extraArgs);
     61 
     62  if (!GeckoChildProcessHost::AsyncLaunch(std::move(extraArgs))) {
     63    mLaunchPhase = LaunchPhase::Complete;
     64    mPrefSerializer = nullptr;
     65    return false;
     66  }
     67  return true;
     68 }
     69 
     70 bool VRProcessParent::WaitForLaunch() {
     71  if (mLaunchPhase == LaunchPhase::Complete) {
     72    return !!mVRChild;
     73  }
     74 
     75  int32_t timeoutMs =
     76      StaticPrefs::dom_vr_process_startup_timeout_ms_AtStartup();
     77 
     78  // If one of the following environment variables are set we can effectively
     79  // ignore the timeout - as we can guarantee the compositor process will be
     80  // terminated
     81  if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS") ||
     82      PR_GetEnv("MOZ_DEBUG_CHILD_PAUSE")) {
     83    timeoutMs = 0;
     84  }
     85 
     86  // Our caller expects the connection to be finished after we return, so we
     87  // immediately set up the IPDL actor and fire callbacks. The IO thread will
     88  // still dispatch a notification to the main thread - we'll just ignore it.
     89  bool result = GeckoChildProcessHost::WaitUntilConnected(timeoutMs);
     90  result &= InitAfterConnect(result);
     91  return result;
     92 }
     93 
     94 void VRProcessParent::Shutdown() {
     95  MOZ_ASSERT(!mShutdownRequested);
     96  mListener = nullptr;
     97 
     98  if (mVRChild) {
     99    // The channel might already be closed if we got here unexpectedly.
    100    if (!mChannelClosed) {
    101      mVRChild->Close();
    102    }
    103    // OnChannelClosed uses this to check if the shutdown was expected or
    104    // unexpected.
    105    mShutdownRequested = true;
    106 
    107 #ifndef NS_FREE_PERMANENT_DATA
    108    // No need to communicate shutdown, the VR process doesn't need to
    109    // communicate anything back.
    110    KillHard("NormalShutdown");
    111 #endif
    112 
    113    // If we're shutting down unexpectedly, we're in the middle of handling an
    114    // ActorDestroy for PVRChild, which is still on the stack. We'll return
    115    // back to OnChannelClosed.
    116    //
    117    // Otherwise, we'll wait for OnChannelClose to be called whenever PVRChild
    118    // acknowledges shutdown.
    119    return;
    120  }
    121 
    122  DestroyProcess();
    123 }
    124 
    125 void VRProcessParent::DestroyProcess() {
    126  if (mLaunchThread) {
    127    // Cancel all tasks. We don't want anything triggering after our caller
    128    // expects this to go away.
    129    {
    130      MonitorAutoLock lock(mMonitor);
    131      mTaskFactory.RevokeAll();
    132    }
    133 
    134    mLaunchThread->Dispatch(NS_NewRunnableFunction("DestroyProcessRunnable",
    135                                                   [this] { Destroy(); }));
    136  }
    137 }
    138 
    139 bool VRProcessParent::InitAfterConnect(bool aSucceeded) {
    140  MOZ_ASSERT(mLaunchPhase == LaunchPhase::Waiting);
    141  MOZ_ASSERT(!mVRChild);
    142 
    143  mLaunchPhase = LaunchPhase::Complete;
    144  mPrefSerializer = nullptr;
    145 
    146  if (aSucceeded) {
    147    GPUChild* gpuChild = GPUProcessManager::Get()->GetGPUChild();
    148    if (!gpuChild) {
    149      NS_WARNING(
    150          "GPU process haven't connected with the parent process yet"
    151          "when creating VR process.");
    152      return false;
    153    }
    154 
    155    if (!StaticPrefs::dom_vr_enabled() &&
    156        !StaticPrefs::dom_vr_webxr_enabled()) {
    157      NS_WARNING("VR is not enabled when trying to create a VRChild");
    158      return false;
    159    }
    160 
    161    mVRChild = MakeRefPtr<VRChild>(this);
    162 
    163    DebugOnly<bool> rv = TakeInitialEndpoint().Bind(mVRChild.get());
    164    MOZ_ASSERT(rv);
    165 
    166    mVRChild->Init();
    167 
    168    if (mListener) {
    169      mListener->OnProcessLaunchComplete(this);
    170    }
    171 
    172    // Make vr-gpu process connection
    173    Endpoint<PVRGPUChild> vrGPUBridge;
    174    VRProcessManager* vpm = VRProcessManager::Get();
    175    DebugOnly<bool> opened =
    176        vpm->CreateGPUBridges(gpuChild->OtherEndpointProcInfo(), &vrGPUBridge);
    177    MOZ_ASSERT(opened);
    178 
    179    (void)gpuChild->SendInitVR(std::move(vrGPUBridge));
    180  }
    181 
    182  return true;
    183 }
    184 
    185 void VRProcessParent::KillHard(const char* aReason) {
    186  ProcessHandle handle = GetChildProcessHandle();
    187  if (!base::KillProcess(handle, base::PROCESS_END_KILLED_BY_USER)) {
    188    NS_WARNING("failed to kill subprocess!");
    189  }
    190 
    191  SetAlreadyDead();
    192 }
    193 
    194 void VRProcessParent::OnChannelConnected(base::ProcessId peer_pid) {
    195  MOZ_ASSERT(!NS_IsMainThread());
    196 
    197  GeckoChildProcessHost::OnChannelConnected(peer_pid);
    198 
    199  // Post a task to the main thread. Take the lock because mTaskFactory is not
    200  // thread-safe.
    201  RefPtr<Runnable> runnable;
    202  {
    203    MonitorAutoLock lock(mMonitor);
    204    runnable = mTaskFactory.NewRunnableMethod(
    205        &VRProcessParent::OnChannelConnectedTask);
    206  }
    207  NS_DispatchToMainThread(runnable);
    208 }
    209 
    210 void VRProcessParent::OnChannelConnectedTask() {
    211  if (mLaunchPhase == LaunchPhase::Waiting) {
    212    InitAfterConnect(true);
    213  }
    214 }
    215 
    216 void VRProcessParent::OnChannelErrorTask() {
    217  if (mLaunchPhase == LaunchPhase::Waiting) {
    218    InitAfterConnect(false);
    219  }
    220 }
    221 
    222 void VRProcessParent::OnChannelClosed() {
    223  mChannelClosed = true;
    224  if (!mShutdownRequested && mListener) {
    225    // This is an unclean shutdown. Notify we're going away.
    226    mListener->OnProcessUnexpectedShutdown(this);
    227  } else {
    228    DestroyProcess();
    229  }
    230 
    231  // Release the actor.
    232  VRChild::Destroy(std::move(mVRChild));
    233  MOZ_ASSERT(!mVRChild);
    234 }
    235 
    236 bool VRProcessParent::IsConnected() const { return !!mVRChild; }
    237 
    238 }  // namespace gfx
    239 }  // namespace mozilla