tor-browser

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

CompositorManagerChild.cpp (9460B)


      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 "mozilla/layers/CompositorManagerChild.h"
      8 
      9 #include "mozilla/StaticPrefs_layers.h"
     10 #include "mozilla/layers/CompositorBridgeChild.h"
     11 #include "mozilla/layers/CompositorManagerParent.h"
     12 #include "mozilla/layers/CompositorThread.h"
     13 #include "mozilla/gfx/CanvasShutdownManager.h"
     14 #include "mozilla/gfx/gfxVars.h"
     15 #include "mozilla/gfx/GPUProcessManager.h"
     16 #include "mozilla/dom/ContentChild.h"  // for ContentChild
     17 #include "mozilla/dom/BrowserChild.h"  // for BrowserChild
     18 #include "mozilla/ipc/Endpoint.h"
     19 #include "VsyncSource.h"
     20 
     21 namespace mozilla {
     22 namespace layers {
     23 
     24 using gfx::GPUProcessManager;
     25 
     26 StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
     27 
     28 static StaticMutex sCompositorProcInfoMutex;
     29 static ipc::EndpointProcInfo sCompositorProcInfo
     30    MOZ_GUARDED_BY(sCompositorProcInfoMutex);
     31 
     32 static void SetCompositorProcInfo(ipc::EndpointProcInfo aInfo) {
     33  StaticMutexAutoLock lock(sCompositorProcInfoMutex);
     34  sCompositorProcInfo = aInfo;
     35 }
     36 
     37 /* static */
     38 ipc::EndpointProcInfo CompositorManagerChild::GetCompositorProcInfo() {
     39  StaticMutexAutoLock lock(sCompositorProcInfoMutex);
     40  return sCompositorProcInfo;
     41 }
     42 
     43 /* static */
     44 bool CompositorManagerChild::IsInitialized(uint64_t aProcessToken) {
     45  MOZ_ASSERT(NS_IsMainThread());
     46  return sInstance && sInstance->CanSend() &&
     47         sInstance->mProcessToken == aProcessToken;
     48 }
     49 
     50 /* static */
     51 void CompositorManagerChild::InitSameProcess(uint32_t aNamespace,
     52                                             uint64_t aProcessToken) {
     53  MOZ_ASSERT(NS_IsMainThread());
     54  if (NS_WARN_IF(IsInitialized(aProcessToken))) {
     55    MOZ_ASSERT_UNREACHABLE("Already initialized same process");
     56    return;
     57  }
     58 
     59  RefPtr<CompositorManagerParent> parent =
     60      CompositorManagerParent::CreateSameProcess(aNamespace);
     61  RefPtr<CompositorManagerChild> child = new CompositorManagerChild(
     62      aProcessToken, aNamespace, /* aSameProcess */ true);
     63  child->SetOtherEndpointProcInfo(ipc::EndpointProcInfo::Current());
     64  if (NS_WARN_IF(!child->Open(parent, CompositorThread(), ipc::ChildSide))) {
     65    MOZ_DIAGNOSTIC_CRASH("Failed to open same process protocol");
     66    return;
     67  }
     68  child->mCanSend = true;
     69  child->SetReplyTimeout();
     70 
     71  parent->BindComplete(/* aIsRoot */ true);
     72  sInstance = std::move(child);
     73  SetCompositorProcInfo(sInstance->OtherEndpointProcInfo());
     74 }
     75 
     76 /* static */
     77 bool CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
     78                                  uint32_t aNamespace,
     79                                  uint64_t aProcessToken /* = 0 */) {
     80  MOZ_ASSERT(NS_IsMainThread());
     81  if (sInstance) {
     82    MOZ_ASSERT(sInstance->mNamespace != aNamespace);
     83  }
     84 
     85  RefPtr<CompositorManagerChild> child =
     86      new CompositorManagerChild(aProcessToken, aNamespace,
     87                                 /* aSameProcess */ false);
     88  if (NS_WARN_IF(!aEndpoint.Bind(child))) {
     89    return false;
     90  }
     91  child->mCanSend = true;
     92  child->SetReplyTimeout();
     93 
     94  sInstance = std::move(child);
     95  SetCompositorProcInfo(sInstance->OtherEndpointProcInfo());
     96 
     97  // If there are any canvases waiting on the recreation of the GPUProcess or
     98  // CompositorManagerChild, then we need to notify them so that they can
     99  // restore their contexts.
    100  gfx::CanvasShutdownManager::OnCompositorManagerRestored();
    101  return true;
    102 }
    103 
    104 /* static */
    105 void CompositorManagerChild::Shutdown() {
    106  MOZ_ASSERT(NS_IsMainThread());
    107  CompositorBridgeChild::ShutDown();
    108 
    109  if (!sInstance) {
    110    return;
    111  }
    112 
    113  sInstance->Close();
    114  sInstance = nullptr;
    115  SetCompositorProcInfo(ipc::EndpointProcInfo::Invalid());
    116 }
    117 
    118 /* static */
    119 void CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken) {
    120  MOZ_ASSERT(NS_IsMainThread());
    121 
    122  // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
    123  // cannot know if the CompositorManagerChild is about to be released but has
    124  // yet to be. As such, we want to pre-emptively set mCanSend to false.
    125  if (sInstance && sInstance->mProcessToken == aProcessToken) {
    126    sInstance->mCanSend = false;
    127    SetCompositorProcInfo(ipc::EndpointProcInfo::Invalid());
    128  }
    129 }
    130 
    131 /* static */
    132 bool CompositorManagerChild::CreateContentCompositorBridge(
    133    uint32_t aNamespace) {
    134  MOZ_ASSERT(NS_IsMainThread());
    135  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
    136    return false;
    137  }
    138 
    139  CompositorBridgeOptions options = ContentCompositorOptions();
    140 
    141  RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
    142  if (NS_WARN_IF(
    143          !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
    144    return false;
    145  }
    146 
    147  bridge->InitForContent(aNamespace);
    148  return true;
    149 }
    150 
    151 /* static */
    152 already_AddRefed<CompositorBridgeChild>
    153 CompositorManagerChild::CreateWidgetCompositorBridge(
    154    uint64_t aProcessToken, WebRenderLayerManager* aLayerManager,
    155    uint32_t aNamespace, CSSToLayoutDeviceScale aScale,
    156    const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
    157    const gfx::IntSize& aSurfaceSize, uint64_t aInnerWindowId) {
    158  MOZ_ASSERT(XRE_IsParentProcess());
    159  MOZ_ASSERT(NS_IsMainThread());
    160  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
    161    return nullptr;
    162  }
    163 
    164  TimeDuration vsyncRate =
    165      gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher()->GetVsyncRate();
    166 
    167  CompositorBridgeOptions options = WidgetCompositorOptions(
    168      aScale, vsyncRate, aOptions, aUseExternalSurfaceSize, aSurfaceSize,
    169      aInnerWindowId);
    170 
    171  RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
    172  if (NS_WARN_IF(
    173          !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
    174    return nullptr;
    175  }
    176 
    177  bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace);
    178  return bridge.forget();
    179 }
    180 
    181 /* static */
    182 already_AddRefed<CompositorBridgeChild>
    183 CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(
    184    WebRenderLayerManager* aLayerManager, uint32_t aNamespace) {
    185  MOZ_ASSERT(XRE_IsParentProcess());
    186  MOZ_ASSERT(NS_IsMainThread());
    187  if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
    188    return nullptr;
    189  }
    190 
    191  CompositorBridgeOptions options = SameProcessWidgetCompositorOptions();
    192 
    193  RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
    194  if (NS_WARN_IF(
    195          !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
    196    return nullptr;
    197  }
    198 
    199  bridge->InitForWidget(1, aLayerManager, aNamespace);
    200  return bridge.forget();
    201 }
    202 
    203 CompositorManagerChild::CompositorManagerChild(uint64_t aProcessToken,
    204                                               uint32_t aNamespace,
    205                                               bool aSameProcess)
    206    : mProcessToken(aProcessToken),
    207      mNamespace(aNamespace),
    208      mResourceId(0),
    209      mCanSend(false),
    210      mSameProcess(aSameProcess),
    211      mFwdTransactionCounter(this) {}
    212 
    213 void CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason) {
    214  mCanSend = false;
    215  if (sInstance == this) {
    216    sInstance = nullptr;
    217  }
    218 }
    219 
    220 void CompositorManagerChild::HandleFatalError(const char* aMsg) {
    221  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
    222 }
    223 
    224 void CompositorManagerChild::ProcessingError(Result aCode,
    225                                             const char* aReason) {
    226  if (aCode != MsgDropped) {
    227    gfxDevCrash(gfx::LogReason::ProcessingError)
    228        << "Processing error in CompositorBridgeChild: " << int(aCode);
    229  }
    230 }
    231 
    232 void CompositorManagerChild::SetReplyTimeout() {
    233 #ifndef DEBUG
    234  // Add a timeout for release builds to kill GPU process when it hangs.
    235  if (XRE_IsParentProcess() && GPUProcessManager::Get()->GetGPUChild()) {
    236    int32_t timeout =
    237        StaticPrefs::layers_gpu_process_ipc_reply_timeout_ms_AtStartup();
    238    SetReplyTimeoutMs(timeout);
    239  }
    240 #endif
    241 }
    242 
    243 bool CompositorManagerChild::ShouldContinueFromReplyTimeout() {
    244  MOZ_ASSERT_IF(mSyncIPCStartTimeStamp.isSome(), XRE_IsParentProcess());
    245 
    246  if (XRE_IsParentProcess()) {
    247 #ifndef DEBUG
    248    // Extend sync IPC reply timeout
    249    if (mSyncIPCStartTimeStamp.isSome()) {
    250      const int32_t maxDurationMs = StaticPrefs::
    251          layers_gpu_process_extend_ipc_reply_timeout_ms_AtStartup();
    252      const auto now = TimeStamp::Now();
    253      const auto durationMs = static_cast<int32_t>(
    254          (now - mSyncIPCStartTimeStamp.ref()).ToMilliseconds());
    255 
    256      if (durationMs < maxDurationMs) {
    257        return true;
    258      }
    259    }
    260 #endif
    261    gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
    262    MOZ_DIAGNOSTIC_ASSERT(GPUProcessManager::Get()->GetGPUChild());
    263    GPUProcessManager::Get()->KillProcess(/* aGenerateMinidump */ true);
    264  }
    265  return false;
    266 }
    267 
    268 mozilla::ipc::IPCResult CompositorManagerChild::RecvNotifyWebRenderError(
    269    const WebRenderError&& aError) {
    270  MOZ_ASSERT(XRE_IsParentProcess());
    271  MOZ_ASSERT(NS_IsMainThread());
    272  GPUProcessManager::Get()->NotifyWebRenderError(aError);
    273  return IPC_OK();
    274 }
    275 
    276 void CompositorManagerChild::SetSyncIPCStartTimeStamp() {
    277  MOZ_ASSERT(mSyncIPCStartTimeStamp.isNothing());
    278 
    279  mSyncIPCStartTimeStamp = Some(TimeStamp::Now());
    280 }
    281 
    282 void CompositorManagerChild::ClearSyncIPCStartTimeStamp() {
    283  mSyncIPCStartTimeStamp = Nothing();
    284 }
    285 
    286 }  // namespace layers
    287 }  // namespace mozilla