tor-browser

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

UiCompositorControllerChild.cpp (11228B)


      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/UiCompositorControllerChild.h"
      8 
      9 #include "mozilla/dom/ContentChild.h"
     10 #include "mozilla/layers/CompositorThread.h"
     11 #include "mozilla/layers/SynchronousTask.h"
     12 #include "mozilla/layers/UiCompositorControllerMessageTypes.h"
     13 #include "mozilla/layers/UiCompositorControllerParent.h"
     14 #include "mozilla/gfx/GPUProcessManager.h"
     15 #include "mozilla/ipc/Endpoint.h"
     16 #include "mozilla/StaticPrefs_layers.h"
     17 #include "mozilla/StaticPtr.h"
     18 #include "nsIWidget.h"
     19 #include "nsProxyRelease.h"
     20 #include "nsThreadUtils.h"
     21 
     22 #if defined(MOZ_WIDGET_ANDROID)
     23 #  include "mozilla/widget/AndroidUiThread.h"
     24 
     25 static RefPtr<nsThread> GetUiThread() { return mozilla::GetAndroidUiThread(); }
     26 #else
     27 static RefPtr<nsThread> GetUiThread() {
     28  MOZ_CRASH("Platform does not support UiCompositorController");
     29  return nullptr;
     30 }
     31 #endif  // defined(MOZ_WIDGET_ANDROID)
     32 
     33 namespace mozilla {
     34 namespace layers {
     35 
     36 // public:
     37 /* static */
     38 RefPtr<UiCompositorControllerChild>
     39 UiCompositorControllerChild::CreateForSameProcess(
     40    const LayersId& aRootLayerTreeId, nsIWidget* aWidget) {
     41  RefPtr<UiCompositorControllerChild> child =
     42      new UiCompositorControllerChild(0, aWidget);
     43  child->mParent = new UiCompositorControllerParent(aRootLayerTreeId);
     44  GetUiThread()->Dispatch(
     45      NewRunnableMethod(
     46          "layers::UiCompositorControllerChild::OpenForSameProcess", child,
     47          &UiCompositorControllerChild::OpenForSameProcess),
     48      nsIThread::DISPATCH_NORMAL);
     49  return child;
     50 }
     51 
     52 /* static */
     53 RefPtr<UiCompositorControllerChild>
     54 UiCompositorControllerChild::CreateForGPUProcess(
     55    const uint64_t& aProcessToken,
     56    Endpoint<PUiCompositorControllerChild>&& aEndpoint, nsIWidget* aWidget) {
     57  RefPtr<UiCompositorControllerChild> child =
     58      new UiCompositorControllerChild(aProcessToken, aWidget);
     59 
     60  RefPtr<nsIRunnable> task =
     61      NewRunnableMethod<Endpoint<PUiCompositorControllerChild>&&>(
     62          "layers::UiCompositorControllerChild::OpenForGPUProcess", child,
     63          &UiCompositorControllerChild::OpenForGPUProcess,
     64          std::move(aEndpoint));
     65 
     66  GetUiThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);
     67  return child;
     68 }
     69 
     70 bool UiCompositorControllerChild::Pause() {
     71  if (!mIsOpen) {
     72    return false;
     73  }
     74  return SendPause();
     75 }
     76 
     77 bool UiCompositorControllerChild::Resume() {
     78  if (!mIsOpen) {
     79    return false;
     80  }
     81  bool resumed = false;
     82  return SendResume(&resumed) && resumed;
     83 }
     84 
     85 bool UiCompositorControllerChild::ResumeAndResize(const int32_t& aX,
     86                                                  const int32_t& aY,
     87                                                  const int32_t& aWidth,
     88                                                  const int32_t& aHeight) {
     89  if (!mIsOpen) {
     90    mResize = Some(gfx::IntRect(aX, aY, aWidth, aHeight));
     91    // Since we are caching these values, pretend the call succeeded.
     92    return true;
     93  }
     94  bool resumed = false;
     95  return SendResumeAndResize(aX, aY, aWidth, aHeight, &resumed) && resumed;
     96 }
     97 
     98 bool UiCompositorControllerChild::InvalidateAndRender() {
     99  if (!mIsOpen) {
    100    return false;
    101  }
    102  return SendInvalidateAndRender();
    103 }
    104 
    105 bool UiCompositorControllerChild::SetMaxToolbarHeight(const int32_t& aHeight) {
    106  if (!mIsOpen) {
    107    mMaxToolbarHeight = Some(aHeight);
    108    // Since we are caching this value, pretend the call succeeded.
    109    return true;
    110  }
    111  return SendMaxToolbarHeight(aHeight);
    112 }
    113 
    114 bool UiCompositorControllerChild::SetFixedBottomOffset(int32_t aOffset) {
    115  return SendFixedBottomOffset(aOffset);
    116 }
    117 
    118 bool UiCompositorControllerChild::ToolbarAnimatorMessageFromUI(
    119    const int32_t& aMessage) {
    120  if (!mIsOpen) {
    121    return false;
    122  }
    123 
    124  if (aMessage == IS_COMPOSITOR_CONTROLLER_OPEN) {
    125    RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
    126  }
    127 
    128  return true;
    129 }
    130 
    131 bool UiCompositorControllerChild::SetDefaultClearColor(const uint32_t& aColor) {
    132  if (!mIsOpen) {
    133    mDefaultClearColor = Some(aColor);
    134    // Since we are caching this value, pretend the call succeeded.
    135    return true;
    136  }
    137 
    138  return SendDefaultClearColor(aColor);
    139 }
    140 
    141 bool UiCompositorControllerChild::RequestScreenPixels() {
    142  if (!mIsOpen) {
    143    return false;
    144  }
    145 
    146  return SendRequestScreenPixels();
    147 }
    148 
    149 bool UiCompositorControllerChild::EnableLayerUpdateNotifications(
    150    const bool& aEnable) {
    151  if (!mIsOpen) {
    152    mLayerUpdateEnabled = Some(aEnable);
    153    // Since we are caching this value, pretend the call succeeded.
    154    return true;
    155  }
    156 
    157  return SendEnableLayerUpdateNotifications(aEnable);
    158 }
    159 
    160 void UiCompositorControllerChild::Destroy() {
    161  MOZ_ASSERT(NS_IsMainThread());
    162 
    163  layers::SynchronousTask task("UiCompositorControllerChild::Destroy");
    164  GetUiThread()->Dispatch(NS_NewRunnableFunction(
    165      "layers::UiCompositorControllerChild::Destroy", [&]() {
    166        MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
    167        AutoCompleteTask complete(&task);
    168 
    169        // Clear the process token so that we don't notify the GPUProcessManager
    170        // about an abnormal shutdown, thereby tearing down the GPU process.
    171        mProcessToken = 0;
    172 
    173        if (mWidget) {
    174          // Dispatch mWidget to main thread to prevent it from being destructed
    175          // by the ui thread.
    176          RefPtr<nsIWidget> widget = std::move(mWidget);
    177          NS_ReleaseOnMainThread("UiCompositorControllerChild::mWidget",
    178                                 widget.forget());
    179        }
    180 
    181        if (mIsOpen) {
    182          // Close the underlying IPC channel.
    183          PUiCompositorControllerChild::Close();
    184          mIsOpen = false;
    185        }
    186      }));
    187 
    188  task.Wait();
    189 }
    190 
    191 bool UiCompositorControllerChild::DeallocPixelBuffer(Shmem& aMem) {
    192  return DeallocShmem(aMem);
    193 }
    194 
    195 // protected:
    196 void UiCompositorControllerChild::ActorDestroy(ActorDestroyReason aWhy) {
    197  mIsOpen = false;
    198  mParent = nullptr;
    199 
    200  if (mProcessToken) {
    201    gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    202    mProcessToken = 0;
    203  }
    204 }
    205 
    206 void UiCompositorControllerChild::ProcessingError(Result aCode,
    207                                                  const char* aReason) {
    208  if (aCode != MsgDropped) {
    209    gfxDevCrash(gfx::LogReason::ProcessingError)
    210        << "Processing error in UiCompositorControllerChild: " << int(aCode);
    211  }
    212 }
    213 
    214 void UiCompositorControllerChild::HandleFatalError(const char* aMsg) {
    215  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
    216 }
    217 
    218 mozilla::ipc::IPCResult
    219 UiCompositorControllerChild::RecvToolbarAnimatorMessageFromCompositor(
    220    const int32_t& aMessage) {
    221 #if defined(MOZ_WIDGET_ANDROID)
    222  if (mWidget) {
    223    mWidget->RecvToolbarAnimatorMessageFromCompositor(aMessage);
    224  }
    225 #endif  // defined(MOZ_WIDGET_ANDROID)
    226 
    227  return IPC_OK();
    228 }
    229 
    230 mozilla::ipc::IPCResult
    231 UiCompositorControllerChild::RecvNotifyCompositorScrollUpdate(
    232    const CompositorScrollUpdate& aUpdate) {
    233  if (mWidget) {
    234    mWidget->NotifyCompositorScrollUpdate(aUpdate);
    235  }
    236 
    237  return IPC_OK();
    238 }
    239 
    240 mozilla::ipc::IPCResult UiCompositorControllerChild::RecvScreenPixels(
    241    ipc::Shmem&& aMem, const ScreenIntSize& aSize, bool aNeedsYFlip) {
    242 #if defined(MOZ_WIDGET_ANDROID)
    243  if (mWidget) {
    244    mWidget->RecvScreenPixels(std::move(aMem), aSize, aNeedsYFlip);
    245  }
    246 #endif  // defined(MOZ_WIDGET_ANDROID)
    247 
    248  return IPC_OK();
    249 }
    250 
    251 // private:
    252 UiCompositorControllerChild::UiCompositorControllerChild(
    253    const uint64_t& aProcessToken, nsIWidget* aWidget)
    254    : mIsOpen(false), mProcessToken(aProcessToken), mWidget(aWidget) {}
    255 
    256 UiCompositorControllerChild::~UiCompositorControllerChild() = default;
    257 
    258 void UiCompositorControllerChild::OpenForSameProcess() {
    259  MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
    260 
    261  mIsOpen = Open(mParent, mozilla::layers::CompositorThread(),
    262                 mozilla::ipc::ChildSide);
    263 
    264  if (!mIsOpen) {
    265    mParent = nullptr;
    266    return;
    267  }
    268 
    269  mParent->InitializeForSameProcess();
    270  SendCachedValues();
    271  // Let Ui thread know the connection is open;
    272  RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
    273 }
    274 
    275 void UiCompositorControllerChild::OpenForGPUProcess(
    276    Endpoint<PUiCompositorControllerChild>&& aEndpoint) {
    277  MOZ_ASSERT(GetUiThread()->IsOnCurrentThread());
    278 
    279  mIsOpen = aEndpoint.Bind(this);
    280 
    281  if (!mIsOpen) {
    282    // The GPU Process Manager might be gone if we receive ActorDestroy very
    283    // late in shutdown.
    284    if (gfx::GPUProcessManager* gpm = gfx::GPUProcessManager::Get()) {
    285      gpm->NotifyRemoteActorDestroyed(mProcessToken);
    286    }
    287    return;
    288  }
    289 
    290  SetReplyTimeout();
    291 
    292  SendCachedValues();
    293  // Let Ui thread know the connection is open;
    294  RecvToolbarAnimatorMessageFromCompositor(COMPOSITOR_CONTROLLER_OPEN);
    295 }
    296 
    297 void UiCompositorControllerChild::SendCachedValues() {
    298  MOZ_ASSERT(mIsOpen);
    299  if (mResize) {
    300    bool resumed;
    301    SendResumeAndResize(mResize.ref().x, mResize.ref().y, mResize.ref().width,
    302                        mResize.ref().height, &resumed);
    303    mResize.reset();
    304  }
    305  if (mMaxToolbarHeight) {
    306    SendMaxToolbarHeight(mMaxToolbarHeight.ref());
    307    mMaxToolbarHeight.reset();
    308  }
    309  if (mDefaultClearColor) {
    310    SendDefaultClearColor(mDefaultClearColor.ref());
    311    mDefaultClearColor.reset();
    312  }
    313  if (mLayerUpdateEnabled) {
    314    SendEnableLayerUpdateNotifications(mLayerUpdateEnabled.ref());
    315    mLayerUpdateEnabled.reset();
    316  }
    317 }
    318 
    319 #ifdef MOZ_WIDGET_ANDROID
    320 void UiCompositorControllerChild::SetCompositorSurfaceManager(
    321    java::CompositorSurfaceManager::Param aCompositorSurfaceManager) {
    322  MOZ_ASSERT(!mCompositorSurfaceManager,
    323             "SetCompositorSurfaceManager must only be called once.");
    324  MOZ_ASSERT(mProcessToken != 0,
    325             "SetCompositorSurfaceManager must only be called for GPU process "
    326             "controllers.");
    327  mCompositorSurfaceManager = aCompositorSurfaceManager;
    328 };
    329 
    330 void UiCompositorControllerChild::OnCompositorSurfaceChanged(
    331    int32_t aWidgetId, java::sdk::Surface::Param aSurface) {
    332  // If mCompositorSurfaceManager is not set then there is no GPU process and
    333  // we do not need to do anything.
    334  if (mCompositorSurfaceManager == nullptr) {
    335    return;
    336  }
    337 
    338  nsresult result =
    339      mCompositorSurfaceManager->OnSurfaceChanged(aWidgetId, aSurface);
    340 
    341  // If our remote binder has died then notify the GPU process manager.
    342  if (NS_FAILED(result)) {
    343    if (mProcessToken) {
    344      gfx::GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    345      mProcessToken = 0;
    346    }
    347  }
    348 }
    349 #endif
    350 
    351 void UiCompositorControllerChild::SetReplyTimeout() {
    352 #ifndef DEBUG
    353  // Add a timeout for release builds to kill GPU process when it hangs.
    354  const int32_t timeout =
    355      StaticPrefs::layers_gpu_process_ipc_reply_timeout_ms_AtStartup();
    356  SetReplyTimeoutMs(timeout);
    357 #endif
    358 }
    359 
    360 bool UiCompositorControllerChild::ShouldContinueFromReplyTimeout() {
    361  gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
    362  gfx::GPUProcessManager::Get()->KillProcess(/* aGenerateMinidump */ true);
    363  return false;
    364 }
    365 
    366 }  // namespace layers
    367 }  // namespace mozilla