chromium/content/browser/media/service_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 "content/browser/media/service_factory.h"

#include <map>
#include <string>
#include <utility>

#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/common/content_client.h"
#include "media/base/cdm_context.h"
#include "media/base/media_switches.h"
#include "media/cdm/cdm_type.h"
#include "media/media_buildflags.h"
#include "media/mojo/mojom/cdm_service.mojom.h"
#include "mojo/public/cpp/bindings/remote_set.h"

#if BUILDFLAG(IS_MAC)
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "sandbox/mac/seatbelt_extension.h"
#endif  // BUILDFLAG(IS_MAC)

#if BUILDFLAG(IS_WIN)
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "media/mojo/mojom/media_foundation_service.mojom.h"
#endif  // BUILDFLAG(IS_WIN)

namespace content {

namespace {

#if BUILDFLAG(IS_MAC)
#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
// TODO(xhwang): Move this to a common place.
const base::FilePath::CharType kSignatureFileExtension[] =
    FILE_PATH_LITERAL(".sig");

// Returns the signature file path given the |file_path|. This function should
// only be used when the signature file and the file are located in the same
// directory, which is the case for the CDM and CDM adapter.
base::FilePath GetSigFilePath(const base::FilePath& file_path) {
  return file_path.AddExtension(kSignatureFileExtension);
}
#endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)

class SeatbeltExtensionTokenProviderImpl final
    : public media::mojom::SeatbeltExtensionTokenProvider {
 public:
  explicit SeatbeltExtensionTokenProviderImpl(const base::FilePath& cdm_path)
      : cdm_path_(cdm_path) {}
  SeatbeltExtensionTokenProviderImpl(
      const SeatbeltExtensionTokenProviderImpl&) = delete;
  SeatbeltExtensionTokenProviderImpl operator=(
      const SeatbeltExtensionTokenProviderImpl&) = delete;
  ~SeatbeltExtensionTokenProviderImpl() override = default;

  void GetTokens(GetTokensCallback callback) override {
    DVLOG(1) << __func__;

    std::vector<sandbox::SeatbeltExtensionToken> tokens;

    // Allow the CDM to be loaded in the CDM service process.
    auto cdm_token = sandbox::SeatbeltExtension::Issue(
        sandbox::SeatbeltExtension::FILE_READ, cdm_path_.value());
    if (cdm_token) {
      tokens.push_back(std::move(*cdm_token));
    } else {
      std::move(callback).Run({});
      return;
    }

#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
    // If CDM host verification is enabled, also allow to open the CDM signature
    // file.
    auto cdm_sig_token =
        sandbox::SeatbeltExtension::Issue(sandbox::SeatbeltExtension::FILE_READ,
                                          GetSigFilePath(cdm_path_).value());
    if (cdm_sig_token) {
      tokens.push_back(std::move(*cdm_sig_token));
    } else {
      std::move(callback).Run({});
      return;
    }
#endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)

    std::move(callback).Run(std::move(tokens));
  }

 private:
  base::FilePath cdm_path_;
};
#endif  // BUILDFLAG(IS_MAC)

#if BUILDFLAG(IS_WIN)
// A singleton running in the browser process to notify (multiple) service
// processes on GpuInfo updates.
class GpuInfoMonitor : public GpuDataManagerObserver {
 public:
  static GpuInfoMonitor* GetInstance() {
    static GpuInfoMonitor* instance = new GpuInfoMonitor();
    return instance;
  }

  GpuInfoMonitor() { GpuDataManager::GetInstance()->AddObserver(this); }

  void RegisterGpuInfoObserver(
      mojo::PendingRemote<media::mojom::GpuInfoObserver> observer) {
    auto observer_id = gpu_info_observers_.Add(std::move(observer));
    // Notify upon registration in case there's a GPUInfo change between
    // `InitializeBroker()` and when this observer is registered.
    gpu_info_observers_.Get(observer_id)
        ->OnGpuInfoUpdate(GpuDataManager::GetInstance()->GetGPUInfo());
  }

  // GpuDataManagerObserver:
  void OnGpuInfoUpdate() override {
    for (const auto& observer : gpu_info_observers_) {
      observer->OnGpuInfoUpdate(GpuDataManager::GetInstance()->GetGPUInfo());
    }
  }

 private:
  mojo::RemoteSet<media::mojom::GpuInfoObserver> gpu_info_observers_;
};

void RegisterGpuInfoObserver(
    mojo::PendingRemote<media::mojom::GpuInfoObserver> observer) {
  GpuInfoMonitor::GetInstance()->RegisterGpuInfoObserver(std::move(observer));
}
#endif  // BUILDFLAG(IS_WIN)

// How long an instance of the service is allowed to sit idle before we
// disconnect and effectively kill it.
constexpr auto kServiceIdleTimeout =;

// Services are keyed on CDM type, user profile and site URL. Note that site
// is not normal URL nor origin. See chrome/browser/site_isolation for details.
ServiceKey;

std::ostream& operator<<(std::ostream& os, const ServiceKey& key) {}

template <typename T>
struct ServiceTraits {};

template <typename BrokerRemoteType>
void InitializeBroker(BrokerRemoteType& broker_remote) {}

template <>
struct ServiceTraits<media::mojom::CdmService> {};

#if BUILDFLAG(IS_WIN)
template <>
struct ServiceTraits<media::mojom::MediaFoundationService> {
  using BrokerType = media::mojom::MediaFoundationServiceBroker;
};

template <>
void InitializeBroker(
    mojo::Remote<media::mojom::MediaFoundationServiceBroker>& broker_remote) {
  broker_remote->UpdateGpuInfo(GpuDataManager::GetInstance()->GetGPUInfo(),
                               base::BindOnce(&RegisterGpuInfoObserver));
}
#endif  // BUILDFLAG(IS_WIN)

// A map hosts all service remotes, each of which corresponds to one service
// process. There should be only one instance of this class stored in
// base::SequenceLocalStorageSlot. See below.
template <typename T>
class ServiceMap {};

template <typename T>
ServiceMap<T>& GetServiceMap() {}

// Erases the service instance identified by `key`.
template <typename T>
void EraseCdmService(const ServiceKey& key) {}

// Gets an instance of the service for `cdm_type`, `browser_context` and `site`.
// Instances are started lazily as needed.
template <typename T>
T& GetService(const media::CdmType& cdm_type,
              BrowserContext* browser_context,
              const GURL& site,
              const std::string& service_name,
              const base::FilePath& cdm_path) {}

}  // namespace

media::mojom::CdmService& GetCdmService(BrowserContext* browser_context,
                                        const GURL& site,
                                        const CdmInfo& cdm_info) {}

#if BUILDFLAG(IS_WIN)
media::mojom::MediaFoundationService& GetMediaFoundationService(
    BrowserContext* browser_context,
    const GURL& site,
    const base::FilePath& cdm_path) {
  return GetService<media::mojom::MediaFoundationService>(
      media::CdmType(), browser_context, site, "Media Foundation Service",
      cdm_path);
}
#endif  // BUILDFLAG(IS_WIN)

}  // namespace content