chromium/ash/components/arc/video_accelerator/oop_arc_video_accelerator_factory.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <utility>

#include "ash/components/arc/video_accelerator/oop_arc_video_accelerator_factory.h"

#include "ash/components/arc/mojom/protected_buffer_manager.mojom.h"
#include "ash/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h"
#include "ash/components/arc/video_accelerator/gpu_arc_video_decoder.h"
#include "ash/components/arc/video_accelerator/protected_buffer_manager.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/task/bind_post_task.h"
#include "chromeos/components/cdm_factory_daemon/chromeos_cdm_factory.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_preferences.h"
#include "media/gpu/macros.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/platform_handle.h"

namespace arc {

namespace {

class MojoProtectedBufferManager : public DecoderProtectedBufferManager {
 public:
  MojoProtectedBufferManager(
      mojo::PendingRemote<mojom::ProtectedBufferManager> pending_remote)
      : remote_(std::move(pending_remote)) {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    // Version 1 introduced GetProtectedNativePixmapHandleFromHandle() and a
    // GetProtectedSharedMemoryFromHandle() variant that returns a nullable
    // value.
    remote_.RequireVersion(1);
  }
  MojoProtectedBufferManager(const MojoProtectedBufferManager&) = delete;
  MojoProtectedBufferManager& operator=(const MojoProtectedBufferManager&) =
      delete;

  // DecoderProtectedBufferManager implementation.
  void GetProtectedSharedMemoryRegionFor(
      base::ScopedFD dummy_fd,
      GetProtectedSharedMemoryRegionForResponseCB response_cb) override {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    remote_->GetProtectedSharedMemoryFromHandle(
        mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(dummy_fd))),
        mojo::WrapCallbackWithDefaultInvokeIfNotRun(
            base::BindPostTaskToCurrentDefault(base::BindOnce(
                &OnGetProtectedSharedMemoryRegionFor, std::move(response_cb))),
            mojo::ScopedSharedBufferHandle()));
  }
  void GetProtectedNativePixmapHandleFor(
      base::ScopedFD dummy_fd,
      GetProtectedNativePixmapHandleForResponseCB response_cb) override {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    // TODO(b/195769334): do we need to validate anything about the response
    // gfx::NativePixmapHandle before calling |response_cb|.
    remote_->GetProtectedNativePixmapHandleFromHandle(
        mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(dummy_fd))),
        mojo::WrapCallbackWithDefaultInvokeIfNotRun(
            base::BindPostTaskToCurrentDefault(base::BindOnce(
                &OnGetProtectedNativePixmapHandleFor, std::move(response_cb))),
            std::nullopt));
  }

 private:
  ~MojoProtectedBufferManager() override = default;

  static void OnGetProtectedSharedMemoryRegionFor(
      GetProtectedSharedMemoryRegionForResponseCB response_cb,
      mojo::ScopedSharedBufferHandle shared_memory_mojo_handle) {
    if (!shared_memory_mojo_handle.is_valid()) {
      return std::move(response_cb).Run(base::UnsafeSharedMemoryRegion());
    }

    // TODO(b/195769334): does anything need to be validated here?
    std::move(response_cb)
        .Run(mojo::UnwrapUnsafeSharedMemoryRegion(
            std::move(shared_memory_mojo_handle)));
  }

  static void OnGetProtectedNativePixmapHandleFor(
      GetProtectedNativePixmapHandleForResponseCB response_cb,
      std::optional<gfx::NativePixmapHandle> native_pixmap_handle) {
    if (!native_pixmap_handle)
      return std::move(response_cb).Run(gfx::NativePixmapHandle());
    // TODO(b/195769334): does anything need to be validated here?
    std::move(response_cb).Run(std::move(*native_pixmap_handle));
  }

  mojo::Remote<mojom::ProtectedBufferManager> remote_;
  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace

// TODO(b/195769334): we should plumb meaningful gpu::GpuPreferences and
// gpu::GpuDriverBugWorkarounds so that we can use them to control behaviors of
// the hardware decoder.
OOPArcVideoAcceleratorFactory::OOPArcVideoAcceleratorFactory(
    mojo::PendingReceiver<mojom::VideoAcceleratorFactory> receiver)
    : receiver_(this, std::move(receiver)) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

OOPArcVideoAcceleratorFactory::~OOPArcVideoAcceleratorFactory() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  weak_ptr_factory_.InvalidateWeakPtrs();
  // Reset |receiver_| now to ensure it doesn't use a partially destroyed
  // *|this|.
  receiver_.reset();
}

void OOPArcVideoAcceleratorFactory::CreateDecodeAccelerator(
    mojo::PendingReceiver<mojom::VideoDecodeAccelerator> receiver,
    mojo::PendingRemote<mojom::ProtectedBufferManager> protected_buffer_manager,
    mojo::PendingRemote<chromeos::cdm::mojom::BrowserCdmFactory>
        browser_cdm_factory) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  VLOGF(2);
  // Note that a well-behaved client should not reach this point twice because
  // there should be one process for each GpuArcVideoDecodeAccelerator. This is
  // guaranteed by arc::GpuArcVideoServiceHost in the browser process. Thus, we
  // don't bother validating that here because if the browser process is
  // compromised, we have bigger problems.
  protected_buffer_manager_ = base::MakeRefCounted<MojoProtectedBufferManager>(
      std::move(protected_buffer_manager));
  mojo::Remote<chromeos::cdm::mojom::BrowserCdmFactory>
      browser_cdm_factory_remote(std::move(browser_cdm_factory));
  chromeos::ChromeOsCdmFactory::SetBrowserCdmFactoryRemote(
      std::move(browser_cdm_factory_remote));
  auto decoder = std::make_unique<GpuArcVideoDecodeAccelerator>(
      gpu::GpuPreferences(), gpu::GpuDriverBugWorkarounds(),
      protected_buffer_manager_);
  auto decoder_receiver =
      mojo::MakeSelfOwnedReceiver(std::move(decoder), std::move(receiver));
  CHECK(decoder_receiver);
  decoder_receiver->set_connection_error_handler(
      base::BindOnce(&OOPArcVideoAcceleratorFactory::OnDecoderDisconnected,
                     weak_ptr_factory_.GetWeakPtr()));
}

void OOPArcVideoAcceleratorFactory::CreateVideoDecoder(
    mojo::PendingReceiver<mojom::VideoDecoder> receiver) {
  // TODO(b/195769334): plumb a ProtectedBufferManager.
  auto decoder = std::make_unique<GpuArcVideoDecoder>(
      /*protected_buffer_manager=*/nullptr);
  auto decoder_receiver =
      mojo::MakeSelfOwnedReceiver(std::move(decoder), std::move(receiver));
  CHECK(decoder_receiver);
  decoder_receiver->set_connection_error_handler(
      base::BindOnce(&OOPArcVideoAcceleratorFactory::OnDecoderDisconnected,
                     weak_ptr_factory_.GetWeakPtr()));
}

void OOPArcVideoAcceleratorFactory::CreateEncodeAccelerator(
    mojo::PendingReceiver<mojom::VideoEncodeAccelerator> receiver) {
  NOTIMPLEMENTED();
}

void OOPArcVideoAcceleratorFactory::CreateProtectedBufferAllocator(
    mojo::PendingReceiver<mojom::VideoProtectedBufferAllocator> receiver) {
  NOTREACHED();
}

void OOPArcVideoAcceleratorFactory::OnDecoderDisconnected() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  VLOGF(2);
  receiver_.reset();
}

}  // namespace arc