1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137

media / cdm / cdm_host_files.cc [blame]

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

#include "media/cdm/cdm_host_files.h"

#include <memory>
#include <vector>

#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/scoped_native_library.h"
#include "build/build_config.h"
#include "media/cdm/api/content_decryption_module_ext.h"

namespace media {

namespace {

// TODO(xhwang): Move this to a common place if needed.
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.
base::FilePath GetSigFilePath(const base::FilePath& file_path) {
  return file_path.AddExtension(kSignatureFileExtension);
}

}  // namespace

CdmHostFiles::CdmHostFiles() {
  DVLOG(1) << __func__;
}

CdmHostFiles::~CdmHostFiles() {
  DVLOG(1) << __func__;
}

void CdmHostFiles::Initialize(
    const base::FilePath& cdm_path,
    const std::vector<CdmHostFilePath>& cdm_host_file_paths) {
  OpenCdmFile(cdm_path);
  OpenCommonFiles(cdm_host_file_paths);
}

CdmHostFiles::Status CdmHostFiles::InitVerification(
    base::NativeLibrary cdm_library) {
  DVLOG(1) << __func__;
  DCHECK(cdm_library);

  // Get function pointer exported by the CDM.
  // See media/cdm/api/content_decryption_module_ext.h.
  using InitVerificationFunc =
      bool (*)(const cdm::HostFile* cdm_host_files, uint32_t num_files);
  static const char kInitVerificationFuncName[] = "VerifyCdmHost_0";

  InitVerificationFunc init_verification_func =
      reinterpret_cast<InitVerificationFunc>(
          base::GetFunctionPointerFromNativeLibrary(cdm_library,
                                                    kInitVerificationFuncName));
  if (!init_verification_func) {
    LOG(ERROR) << "Function " << kInitVerificationFuncName << " not found.";
    CloseAllFiles();
    return Status::kGetFunctionFailed;
  }

  // Fills |cdm_host_files| with common and CDM specific files.
  std::vector<cdm::HostFile> cdm_host_files;
  TakePlatformFiles(&cdm_host_files);

  // std::vector::data() is not guaranteed to be nullptr when empty().
  const cdm::HostFile* cdm_host_files_ptr =
      cdm_host_files.empty() ? nullptr : cdm_host_files.data();

  // Call |init_verification_func| on the CDM with |cdm_host_files|. Note that
  // the ownership of these files are transferred to the CDM, which will close
  // the files immediately after use.
  VLOG(1) << __func__ << ": Calling " << kInitVerificationFuncName << "() with "
          << cdm_host_files.size() << " files.";
  for (const auto& host_file : cdm_host_files) {
    VLOG(1) << " - File Path: " << host_file.file_path;
    VLOG(1) << " - File: " << host_file.file;
    VLOG(1) << " - Sig File: " << host_file.sig_file;
  }

  if (!init_verification_func(cdm_host_files_ptr, cdm_host_files.size())) {
    LOG(ERROR) << "Failed to verify CDM host.";
    CloseAllFiles();
    return Status::kInitVerificationFailed;
  }

  // Close all files not passed to the CDM.
  CloseAllFiles();
  return Status::kSuccess;
}

void CdmHostFiles::CloseAllFiles() {
  common_files_.clear();
  cdm_specific_files_.clear();
}

void CdmHostFiles::OpenCommonFiles(
    const std::vector<CdmHostFilePath>& cdm_host_file_paths) {
  DCHECK(common_files_.empty());

  for (const auto& value : cdm_host_file_paths) {
    common_files_.push_back(
        CdmHostFile::Create(value.file_path, value.sig_file_path));
  }
}

void CdmHostFiles::OpenCdmFile(const base::FilePath& cdm_path) {
  DCHECK(!cdm_path.empty());
  cdm_specific_files_.push_back(
      CdmHostFile::Create(cdm_path, GetSigFilePath(cdm_path)));
}

void CdmHostFiles::TakePlatformFiles(
    std::vector<cdm::HostFile>* cdm_host_files) {
  DCHECK(cdm_host_files->empty());

  // Populate an array of cdm::HostFile.
  for (const auto& file : common_files_)
    cdm_host_files->push_back(file->TakePlatformFile());
  for (const auto& file : cdm_specific_files_)
    cdm_host_files->push_back(file->TakePlatformFile());
}

}  // namespace media