tor-browser

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

VideoBridgeParent.cpp (9891B)


      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 "VideoBridgeParent.h"
      8 #include "CompositorThread.h"
      9 #include "mozilla/DataMutex.h"
     10 #include "mozilla/ipc/Endpoint.h"
     11 #include "mozilla/layers/PTextureParent.h"
     12 #include "mozilla/layers/TextureHost.h"
     13 #include "mozilla/layers/VideoBridgeUtils.h"
     14 #include "mozilla/webrender/RenderThread.h"
     15 
     16 namespace mozilla::layers {
     17 
     18 using namespace mozilla::ipc;
     19 using namespace mozilla::gfx;
     20 
     21 using VideoBridgeTable = EnumeratedArray<VideoBridgeSource, VideoBridgeParent*,
     22                                         size_t(VideoBridgeSource::_Count)>;
     23 
     24 NS_IMPL_NONLOGGING_ADDREF_INHERITED(VideoBridgeParent, HostIPCAllocator)
     25 NS_IMPL_NONLOGGING_RELEASE_INHERITED(VideoBridgeParent, HostIPCAllocator)
     26 
     27 MOZ_RUNINIT static StaticDataMutex<VideoBridgeTable> sVideoBridgeFromProcess(
     28    "VideoBridges");
     29 static Atomic<bool> sVideoBridgeParentShutDown(false);
     30 
     31 VideoBridgeParent::VideoBridgeParent(VideoBridgeSource aSource)
     32    : mMonitor("VideoBridgeParent::mMonitor"),
     33      mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()),
     34      mClosed(false) {
     35  auto videoBridgeFromProcess = sVideoBridgeFromProcess.Lock();
     36  switch (aSource) {
     37    case VideoBridgeSource::RddProcess:
     38    case VideoBridgeSource::GpuProcess:
     39    case VideoBridgeSource::MFMediaEngineCDMProcess:
     40      (*videoBridgeFromProcess)[aSource] = this;
     41      break;
     42    default:
     43      MOZ_CRASH("Unhandled case");
     44  }
     45 }
     46 
     47 VideoBridgeParent::~VideoBridgeParent() {
     48  auto videoBridgeFromProcess = sVideoBridgeFromProcess.Lock();
     49  for (auto& bridgeParent : *videoBridgeFromProcess) {
     50    if (bridgeParent == this) {
     51      bridgeParent = nullptr;
     52    }
     53  }
     54 }
     55 
     56 /* static */
     57 void VideoBridgeParent::Open(Endpoint<PVideoBridgeParent>&& aEndpoint,
     58                             VideoBridgeSource aSource) {
     59  RefPtr<VideoBridgeParent> parent = new VideoBridgeParent(aSource);
     60 
     61  CompositorThread()->Dispatch(
     62      NewRunnableMethod<Endpoint<PVideoBridgeParent>&&>(
     63          "gfx::layers::VideoBridgeParent::Bind", parent,
     64          &VideoBridgeParent::Bind, std::move(aEndpoint)));
     65 }
     66 
     67 void VideoBridgeParent::Bind(Endpoint<PVideoBridgeParent>&& aEndpoint) {
     68  if (!aEndpoint.Bind(this)) {
     69    // We can't recover from this.
     70    MOZ_CRASH("Failed to bind VideoBridgeParent to endpoint");
     71  }
     72 }
     73 
     74 /* static */
     75 RefPtr<VideoBridgeParent> VideoBridgeParent::GetSingleton(
     76    const Maybe<VideoBridgeSource>& aSource) {
     77  MOZ_ASSERT(aSource.isSome());
     78  auto videoBridgeFromProcess = sVideoBridgeFromProcess.Lock();
     79  switch (aSource.value()) {
     80    case VideoBridgeSource::RddProcess:
     81    case VideoBridgeSource::GpuProcess:
     82    case VideoBridgeSource::MFMediaEngineCDMProcess:
     83      MOZ_ASSERT((*videoBridgeFromProcess)[aSource.value()]);
     84      return RefPtr{(*videoBridgeFromProcess)[aSource.value()]};
     85    default:
     86      MOZ_CRASH("Unhandled case");
     87  }
     88 }
     89 
     90 already_AddRefed<TextureHost> VideoBridgeParent::LookupTextureAsync(
     91    const dom::ContentParentId& aContentId, uint64_t aSerial) {
     92  MonitorAutoLock lock(mMonitor);
     93 
     94  // We raced shutting down the actor. This can happen when another thread is
     95  // keeping the VideoBridgeParent object alive, by waiting for a texture lookup
     96  // to complete. While the lookup should fail quickly, it may not release the
     97  // actor in time to have removed it from the singleton array.
     98  if (NS_WARN_IF(!mCompositorThreadHolder)) {
     99    return nullptr;
    100  }
    101 
    102  MOZ_ASSERT(mCompositorThreadHolder->IsInThread());
    103 
    104  auto* actor = mTextureMap[aSerial];
    105  if (NS_WARN_IF(!actor)) {
    106    return nullptr;
    107  }
    108 
    109  if (NS_WARN_IF(aContentId != TextureHost::GetTextureContentId(actor))) {
    110    return nullptr;
    111  }
    112 
    113  return do_AddRef(TextureHost::AsTextureHost(actor));
    114 }
    115 
    116 already_AddRefed<TextureHost> VideoBridgeParent::LookupTexture(
    117    const dom::ContentParentId& aContentId, uint64_t aSerial) {
    118  MonitorAutoLock lock(mMonitor);
    119 
    120  // We raced shutting down the actor.
    121  if (NS_WARN_IF(!mCompositorThreadHolder)) {
    122    return nullptr;
    123  }
    124 
    125  auto* actor = mTextureMap[aSerial];
    126  if (actor) {
    127    if (NS_WARN_IF(aContentId != TextureHost::GetTextureContentId(actor))) {
    128      return nullptr;
    129    }
    130    return do_AddRef(TextureHost::AsTextureHost(actor));
    131  }
    132 
    133  // We cannot block on the Compositor thread because that is the thread we get
    134  // the IPC calls for the update on.
    135  if (NS_WARN_IF(mCompositorThreadHolder->IsInThread())) {
    136    MOZ_ASSERT_UNREACHABLE("Should never call on Compositor thread!");
    137    return nullptr;
    138  }
    139 
    140  // Canvas may have raced ahead of VideoBridgeParent setting up the
    141  // PTextureParent IPDL object. This should happen only rarely/briefly. Since
    142  // we know that the PTexture constructor must be in the send queue, we can
    143  // block until the IPDL ping comes back.
    144  bool complete = false;
    145 
    146  auto resolve = [&](void_t&&) {
    147    MonitorAutoLock lock(mMonitor);
    148    complete = true;
    149    lock.NotifyAll();
    150  };
    151 
    152  auto reject = [&](ipc::ResponseRejectReason) {
    153    MonitorAutoLock lock(mMonitor);
    154    complete = true;
    155    lock.NotifyAll();
    156  };
    157 
    158  mCompositorThreadHolder->Dispatch(
    159      NS_NewRunnableFunction("VideoBridgeParent::LookupTexture", [&]() {
    160        if (CanSend()) {
    161          SendPing(std::move(resolve), std::move(reject));
    162        } else {
    163          reject(ipc::ResponseRejectReason::ChannelClosed);
    164        }
    165      }));
    166 
    167  while (!complete) {
    168    lock.Wait();
    169  }
    170 
    171  actor = mTextureMap[aSerial];
    172  if (!actor) {
    173    return nullptr;
    174  }
    175 
    176  if (NS_WARN_IF(aContentId != TextureHost::GetTextureContentId(actor))) {
    177    return nullptr;
    178  }
    179 
    180  return do_AddRef(TextureHost::AsTextureHost(actor));
    181 }
    182 
    183 void VideoBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
    184  bool shutdown = sVideoBridgeParentShutDown;
    185 
    186  if (!shutdown && aWhy == AbnormalShutdown) {
    187    gfxCriticalNote
    188        << "VideoBridgeParent receives IPC close with reason=AbnormalShutdown";
    189  }
    190 
    191  {
    192    MonitorAutoLock lock(mMonitor);
    193    // Can't alloc/dealloc shmems from now on.
    194    mClosed = true;
    195    mCompositorThreadHolder = nullptr;
    196  }
    197 }
    198 
    199 /* static */
    200 void VideoBridgeParent::Shutdown() {
    201  CompositorThread()->Dispatch(NS_NewRunnableFunction(
    202      "VideoBridgeParent::Shutdown",
    203      []() -> void { VideoBridgeParent::ShutdownInternal(); }));
    204 }
    205 
    206 /* static */
    207 void VideoBridgeParent::ShutdownInternal() {
    208  sVideoBridgeParentShutDown = true;
    209 
    210  nsTArray<RefPtr<VideoBridgeParent>> bridges;
    211 
    212  // We don't want to hold the sVideoBridgeFromProcess lock when the
    213  // VideoBridgeParent objects are closed without holding a reference to them.
    214  {
    215    auto videoBridgeFromProcess = sVideoBridgeFromProcess.Lock();
    216    for (auto& bridgeParent : *videoBridgeFromProcess) {
    217      if (bridgeParent) {
    218        bridges.AppendElement(bridgeParent);
    219      }
    220    }
    221  }
    222 
    223  for (auto& bridge : bridges) {
    224    bridge->Close();
    225  }
    226 }
    227 
    228 /* static */
    229 void VideoBridgeParent::UnregisterExternalImages() {
    230  MOZ_ASSERT(sVideoBridgeParentShutDown);
    231 
    232  auto videoBridgeFromProcess = sVideoBridgeFromProcess.Lock();
    233  for (auto& bridgeParent : *videoBridgeFromProcess) {
    234    if (bridgeParent) {
    235      bridgeParent->DoUnregisterExternalImages();
    236    }
    237  }
    238 }
    239 
    240 void VideoBridgeParent::DoUnregisterExternalImages() {
    241  const ManagedContainer<PTextureParent>& textures = ManagedPTextureParent();
    242  for (const auto& key : textures) {
    243    RefPtr<TextureHost> texture = TextureHost::AsTextureHost(key);
    244 
    245    if (texture) {
    246      texture->MaybeDestroyRenderTexture();
    247    }
    248  }
    249 }
    250 
    251 PTextureParent* VideoBridgeParent::AllocPTextureParent(
    252    const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
    253    const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
    254    const dom::ContentParentId& aContentId, const uint64_t& aSerial) {
    255  PTextureParent* parent = TextureHost::CreateIPDLActor(
    256      this, aSharedData, std::move(aReadLock), aLayersBackend, aFlags,
    257      aContentId, aSerial, Nothing());
    258 
    259  if (!parent) {
    260    return nullptr;
    261  }
    262 
    263  MonitorAutoLock lock(mMonitor);
    264  mTextureMap[aSerial] = parent;
    265  return parent;
    266 }
    267 
    268 bool VideoBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
    269  MonitorAutoLock lock(mMonitor);
    270  mTextureMap.erase(TextureHost::GetTextureSerial(actor));
    271  return TextureHost::DestroyIPDLActor(actor);
    272 }
    273 
    274 void VideoBridgeParent::SendAsyncMessage(
    275    const nsTArray<AsyncParentMessageData>& aMessage) {
    276  MOZ_ASSERT(false, "AsyncMessages not supported");
    277 }
    278 
    279 bool VideoBridgeParent::AllocShmem(size_t aSize, ipc::Shmem* aShmem) {
    280  {
    281    MonitorAutoLock lock(mMonitor);
    282    if (mClosed) {
    283      return false;
    284    }
    285  }
    286  return PVideoBridgeParent::AllocShmem(aSize, aShmem);
    287 }
    288 
    289 bool VideoBridgeParent::AllocUnsafeShmem(size_t aSize, ipc::Shmem* aShmem) {
    290  {
    291    MonitorAutoLock lock(mMonitor);
    292    if (mClosed) {
    293      return false;
    294    }
    295  }
    296  return PVideoBridgeParent::AllocUnsafeShmem(aSize, aShmem);
    297 }
    298 
    299 bool VideoBridgeParent::DeallocShmem(ipc::Shmem& aShmem) {
    300  {
    301    MonitorAutoLock lock(mMonitor);
    302    if (mCompositorThreadHolder && !mCompositorThreadHolder->IsInThread()) {
    303      mCompositorThreadHolder->Dispatch(NS_NewRunnableFunction(
    304          "gfx::layers::VideoBridgeParent::DeallocShmem",
    305          [self = RefPtr{this}, shmem = std::move(aShmem)]() mutable {
    306            self->DeallocShmem(shmem);
    307          }));
    308      return true;
    309    }
    310 
    311    if (mClosed) {
    312      return false;
    313    }
    314  }
    315 
    316  return PVideoBridgeParent::DeallocShmem(aShmem);
    317 }
    318 
    319 bool VideoBridgeParent::IsSameProcess() const {
    320  return OtherPid() == base::GetCurrentProcId();
    321 }
    322 
    323 void VideoBridgeParent::NotifyNotUsed(PTextureParent* aTexture,
    324                                      uint64_t aTransactionId) {}
    325 
    326 }  // namespace mozilla::layers