tor-browser

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

VRProcessManager.cpp (8058B)


      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 "VRProcessManager.h"
      8 
      9 #include "VRProcessParent.h"
     10 #include "VRChild.h"
     11 #include "VRGPUChild.h"
     12 #include "VRGPUParent.h"
     13 #include "mozilla/dom/ContentParent.h"
     14 #include "mozilla/gfx/Logging.h"
     15 #include "mozilla/ipc/Endpoint.h"
     16 #include "mozilla/MemoryReportingProcess.h"
     17 #include "mozilla/Preferences.h"
     18 
     19 namespace mozilla {
     20 namespace gfx {
     21 
     22 static StaticAutoPtr<VRProcessManager> sSingleton;
     23 
     24 /* static */
     25 VRProcessManager* VRProcessManager::Get() { return sSingleton; }
     26 
     27 /* static */
     28 void VRProcessManager::Initialize() {
     29  MOZ_ASSERT(XRE_IsParentProcess());
     30  if (sSingleton == nullptr) {
     31    sSingleton = new VRProcessManager();
     32  }
     33 }
     34 
     35 /* static */
     36 void VRProcessManager::Shutdown() { sSingleton = nullptr; }
     37 
     38 VRProcessManager::VRProcessManager() : mProcess(nullptr), mVRChild(nullptr) {
     39  MOZ_COUNT_CTOR(VRProcessManager);
     40 
     41  mObserver = new Observer(this);
     42  nsContentUtils::RegisterShutdownObserver(mObserver);
     43  Preferences::AddStrongObserver(mObserver, "");
     44 }
     45 
     46 VRProcessManager::~VRProcessManager() {
     47  MOZ_COUNT_DTOR(VRProcessManager);
     48 
     49  if (mObserver) {
     50    nsContentUtils::UnregisterShutdownObserver(mObserver);
     51    Preferences::RemoveObserver(mObserver, "");
     52    mObserver = nullptr;
     53  }
     54 
     55  DestroyProcess();
     56  // The VR process should have already been shut down.
     57  MOZ_ASSERT(!mProcess);
     58 }
     59 
     60 void VRProcessManager::LaunchVRProcess() {
     61  if (mProcess) {
     62    return;
     63  }
     64 
     65  // The subprocess is launched asynchronously, so we wait for a callback to
     66  // acquire the IPDL actor.
     67  mProcess = new VRProcessParent(this);
     68  if (!mProcess->Launch()) {
     69    DisableVRProcess("Failed to launch VR process");
     70  }
     71 }
     72 
     73 void VRProcessManager::DisableVRProcess(const char* aMessage) {
     74  if (!StaticPrefs::dom_vr_process_enabled_AtStartup()) {
     75    return;
     76  }
     77 
     78  DestroyProcess();
     79 }
     80 
     81 void VRProcessManager::DestroyProcess() {
     82  if (!mProcess) {
     83    return;
     84  }
     85 
     86  mProcess->Shutdown();
     87  mProcess = nullptr;
     88  mVRChild = nullptr;
     89 
     90  CrashReporter::RecordAnnotationCString(
     91      CrashReporter::Annotation::VRProcessStatus, "Destroyed");
     92 }
     93 
     94 bool VRProcessManager::EnsureVRReady() {
     95  if (mProcess && !mProcess->IsConnected()) {
     96    if (!mProcess->WaitForLaunch()) {
     97      // If this fails, we should have fired OnProcessLaunchComplete and
     98      // removed the process.
     99      MOZ_ASSERT(!mProcess && !mVRChild);
    100      return false;
    101    }
    102  }
    103 
    104  if (mVRChild) {
    105    if (mVRChild->EnsureVRReady()) {
    106      return true;
    107    }
    108 
    109    // If the initialization above fails, we likely have a GPU process teardown
    110    // waiting in our message queue (or will soon). We need to ensure we don't
    111    // restart it later because if we fail here, our callers assume they should
    112    // fall back to a combined UI/GPU process. This also ensures our internal
    113    // state is consistent (e.g. process token is reset).
    114    DisableVRProcess("Failed to initialize VR process");
    115  }
    116 
    117  return false;
    118 }
    119 
    120 void VRProcessManager::OnProcessLaunchComplete(VRProcessParent* aParent) {
    121  MOZ_ASSERT(mProcess && mProcess == aParent);
    122 
    123  mVRChild = mProcess->GetActor();
    124 
    125  if (!mProcess->IsConnected()) {
    126    DestroyProcess();
    127    return;
    128  }
    129 
    130  // Flush any pref updates that happened during launch and weren't
    131  // included in the blobs set up in LaunchGPUProcess.
    132  for (const mozilla::dom::Pref& pref : mQueuedPrefs) {
    133    (void)NS_WARN_IF(!mVRChild->SendPreferenceUpdate(pref));
    134  }
    135  mQueuedPrefs.Clear();
    136 
    137  CrashReporter::RecordAnnotationCString(
    138      CrashReporter::Annotation::VRProcessStatus, "Running");
    139 }
    140 
    141 void VRProcessManager::OnProcessUnexpectedShutdown(VRProcessParent* aParent) {
    142  MOZ_ASSERT(mProcess && mProcess == aParent);
    143 
    144  DestroyProcess();
    145 }
    146 
    147 bool VRProcessManager::CreateGPUBridges(
    148    mozilla::ipc::EndpointProcInfo aOtherProcess,
    149    mozilla::ipc::Endpoint<PVRGPUChild>* aOutVRBridge) {
    150  if (!CreateGPUVRManager(aOtherProcess, aOutVRBridge)) {
    151    return false;
    152  }
    153  return true;
    154 }
    155 
    156 bool VRProcessManager::CreateGPUVRManager(
    157    mozilla::ipc::EndpointProcInfo aOtherProcess,
    158    mozilla::ipc::Endpoint<PVRGPUChild>* aOutEndpoint) {
    159  if (mProcess && !mProcess->IsConnected()) {
    160    NS_WARNING("VR process haven't connected with the parent process yet");
    161    return false;
    162  }
    163 
    164  ipc::EndpointProcInfo vrparentInfo =
    165      mProcess ? ipc::EndpointProcInfo{.mPid = mProcess->GetChildProcessId(),
    166                                       .mChildID = mProcess->GetChildID()}
    167               : ipc::EndpointProcInfo::Current();
    168 
    169  ipc::Endpoint<PVRGPUParent> vrparentPipe;
    170  ipc::Endpoint<PVRGPUChild> vrchildPipe;
    171  nsresult rv = PVRGPU::CreateEndpoints(vrparentInfo, aOtherProcess,
    172                                        &vrparentPipe, &vrchildPipe);
    173 
    174  if (NS_FAILED(rv)) {
    175    gfxCriticalNote << "Could not create gpu-vr bridge: " << hexa(int(rv));
    176    return false;
    177  }
    178 
    179  // Bind vr-gpu pipe to VRParent and make a PVRGPU connection.
    180  VRChild* vrChild = mProcess->GetActor();
    181  vrChild->SendNewGPUVRManager(std::move(vrparentPipe));
    182 
    183  *aOutEndpoint = std::move(vrchildPipe);
    184  return true;
    185 }
    186 
    187 NS_IMPL_ISUPPORTS(VRProcessManager::Observer, nsIObserver);
    188 
    189 VRProcessManager::Observer::Observer(VRProcessManager* aManager)
    190    : mManager(aManager) {}
    191 
    192 NS_IMETHODIMP
    193 VRProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic,
    194                                    const char16_t* aData) {
    195  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
    196    mManager->OnXPCOMShutdown();
    197  } else if (!strcmp(aTopic, "nsPref:changed")) {
    198    mManager->OnPreferenceChange(aData);
    199  }
    200  return NS_OK;
    201 }
    202 
    203 void VRProcessManager::CleanShutdown() { DestroyProcess(); }
    204 
    205 void VRProcessManager::OnXPCOMShutdown() {
    206  if (mObserver) {
    207    nsContentUtils::UnregisterShutdownObserver(mObserver);
    208    Preferences::RemoveObserver(mObserver, "");
    209    mObserver = nullptr;
    210  }
    211 
    212  CleanShutdown();
    213 }
    214 
    215 void VRProcessManager::OnPreferenceChange(const char16_t* aData) {
    216  // We know prefs are ASCII here.
    217  NS_LossyConvertUTF16toASCII strData(aData);
    218 
    219  mozilla::dom::Pref pref(strData, /* isLocked */ false,
    220                          /* isSanitized */ false, Nothing(), Nothing());
    221 
    222  Preferences::GetPreference(&pref, GeckoProcessType_VR,
    223                             /* remoteType */ ""_ns);
    224  if (!!mVRChild) {
    225    MOZ_ASSERT(mQueuedPrefs.IsEmpty());
    226    mVRChild->SendPreferenceUpdate(pref);
    227  } else {
    228    mQueuedPrefs.AppendElement(pref);
    229  }
    230 }
    231 
    232 VRChild* VRProcessManager::GetVRChild() { return mProcess->GetActor(); }
    233 
    234 class VRMemoryReporter : public MemoryReportingProcess {
    235 public:
    236  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRMemoryReporter, override)
    237 
    238  bool IsAlive() const override {
    239    if (VRProcessManager* vpm = VRProcessManager::Get()) {
    240      return !!vpm->GetVRChild();
    241    }
    242    return false;
    243  }
    244 
    245  bool SendRequestMemoryReport(
    246      const uint32_t& aGeneration, const bool& aAnonymize,
    247      const bool& aMinimizeMemoryUsage,
    248      const Maybe<ipc::FileDescriptor>& aDMDFile) override {
    249    VRChild* child = GetChild();
    250    if (!child) {
    251      return false;
    252    }
    253 
    254    return child->SendRequestMemoryReport(aGeneration, aAnonymize,
    255                                          aMinimizeMemoryUsage, aDMDFile);
    256  }
    257 
    258  int32_t Pid() const override {
    259    if (VRChild* child = GetChild()) {
    260      return (int32_t)child->OtherPid();
    261    }
    262    return 0;
    263  }
    264 
    265 private:
    266  VRChild* GetChild() const {
    267    if (VRProcessManager* vpm = VRProcessManager::Get()) {
    268      if (VRChild* child = vpm->GetVRChild()) {
    269        return child;
    270      }
    271    }
    272    return nullptr;
    273  }
    274 
    275 protected:
    276  ~VRMemoryReporter() = default;
    277 };
    278 
    279 RefPtr<MemoryReportingProcess> VRProcessManager::GetProcessMemoryReporter() {
    280  if (!EnsureVRReady()) {
    281    return nullptr;
    282  }
    283  return new VRMemoryReporter();
    284 }
    285 
    286 }  // namespace gfx
    287 }  // namespace mozilla