Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(263)

Side by Side Diff: content/common/media/cdm_host_files.cc

Issue 2582463003: media: Verify CDM Host files (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/common/media/cdm_host_files.h"
6
7 #include <map>
8 #include <memory>
9 #include <vector>
10
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/native_library.h"
17 #include "base/path_service.h"
18 #include "content/common/media/cdm_host_file.h"
19 #include "media/cdm/cdm_paths.h"
20 // TODO(xhwang): This should be replaced with "media/cdm/api/..."
21 #include "media/cdm/content_decryption_module_ext.h"
22
23 #if defined(POSIX_WITH_ZYGOTE)
24 #include "content/common/pepper_plugin_list.h"
25 #include "content/public/common/pepper_plugin_info.h"
26 #endif
27
28 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
29
30 namespace content {
31
32 namespace {
33
34 // Returns the CDM library file name given the |cdm_adapter_file_name|. Returns
35 // nullptr if |cdm_adapter_file_name| does not correspond to a known CDM.
36 const char* GetCdmFileName(const base::FilePath& cdm_adapter_file_name) {
Greg K 2017/01/09 21:45:14 How is the CDM library file name different from th
xhwang 2017/01/12 20:15:02 For example: Widevine CDM adapter file name: libwi
37 #if defined(WIDEVINE_CDM_AVAILABLE)
38 if (cdm_adapter_file_name ==
39 base::FilePath::FromUTF8Unsafe(kWidevineCdmAdapterFileName))
40 return kWidevineCdmLibraryName;
41 #endif
42
43 // Clear Key CDM. For test only.
44 if (cdm_adapter_file_name ==
45 base::FilePath::FromUTF8Unsafe(media::kClearKeyCdmAdapterFileName))
46 return media::kClearKeyCdmLibraryName;
47
48 return nullptr;
49 }
50
51 // Returns the path to the CDM binary given the |cdm_adapter_path|. Returns an
52 // empty path if |cdm_adapter_path| does not correspond to a known CDM.
53 base::FilePath GetCdmPath(const base::FilePath& cdm_adapter_path) {
54 const char* cdm_file_name = GetCdmFileName(cdm_adapter_path.BaseName());
55 if (!cdm_file_name)
56 return base::FilePath();
57
58 return cdm_adapter_path.DirName().AppendASCII(
59 base::GetNativeLibraryName(cdm_file_name));
jrummell 2016/12/16 20:21:30 Is this needed? kClearKeyCdmAdapterFileName return
xhwang 2017/01/12 20:15:02 GetCdmFileName() returns kClearKeyCdmLibraryName w
60 }
61
62 // From the list of registered plugins, finds all registered CDMs and fills
63 // |cdm_adapter_paths| with found CDM adapters paths.
64 void GetRegisteredCdms(std::vector<base::FilePath>* cdm_adapter_paths) {
65 std::vector<PepperPluginInfo> plugins;
66 ComputePepperPluginList(&plugins);
67 for (const auto& plugin : plugins) {
68 // CDM is not an internal plugin.
69 if (plugin.is_internal)
70 continue;
71
72 if (IsCdm(plugin.path))
73 cdm_adapter_paths->push_back(plugin.path);
74 }
75 }
76
77 #if defined(POSIX_WITH_ZYGOTE)
78 // A global instance used on Linux where we have to open the files in the
79 // Zygote process.
80 // TODO(xhwang): Make this Linux only.
81 base::LazyInstance<std::unique_ptr<CdmHostFiles>> g_cdm_host_files =
82 LAZY_INSTANCE_INITIALIZER;
83 #endif
84
85 } // namespace
86
87 CdmHostFiles::CdmHostFiles() {
88 DVLOG(1) << __func__;
89 }
90
91 CdmHostFiles::~CdmHostFiles() {
92 DVLOG(1) << __func__;
93 }
94
95 #if defined(POSIX_WITH_ZYGOTE)
96 // static
97 void CdmHostFiles::CreateGlobalInstance() {
98 DVLOG(1) << __func__;
99 DCHECK(!g_cdm_host_files.Get().get());
100
101 std::unique_ptr<CdmHostFiles> cdm_host_files =
102 base::MakeUnique<CdmHostFiles>();
103 if (!cdm_host_files->OpenFilesForAllRegisteredCdms()) {
104 DVLOG(1) << __func__ << " failed.";
105 cdm_host_files.reset();
106 return;
107 }
108
109 g_cdm_host_files.Get().reset(cdm_host_files.release());
110 }
111
112 // static
113 std::unique_ptr<CdmHostFiles> CdmHostFiles::TakeGlobalInstance() {
114 return std::move(g_cdm_host_files.Get());
115 }
116 #endif
117
118 // static
119 std::unique_ptr<CdmHostFiles> CdmHostFiles::Create(
120 const base::FilePath& cdm_adapter_path) {
121 DVLOG(1) << __func__;
122 std::unique_ptr<CdmHostFiles> cdm_host_files =
123 base::MakeUnique<CdmHostFiles>();
124 if (!cdm_host_files->OpenFiles(cdm_adapter_path)) {
125 cdm_host_files.reset();
126 return nullptr;
127 }
128
129 return cdm_host_files;
130 }
131
132 void CdmHostFiles::VerifyFiles(base::NativeLibrary library,
133 const base::FilePath& cdm_adapter_path) {
134 DCHECK(library);
135
136 // Get VerifyHost() function pointer exported by the CDM.
137 using VerifyHostFilesFunc =
138 bool (*)(const cdm::CdmHostFile* cdm_host_files, uint32_t num_files);
139 static const char kVerifyHostFilesFuncName[] = "VerifyHostFiles";
140
141 // On POSIX, the |library| is the adapter. This works because "the dlsym()
142 // function shall search for the named symbol in all objects loaded
143 // automatically as a result of loading the object referenced by handle".
144 // In this case, the CDM is loaded automatically as a result of loading the
145 // CDM adapter.
146 // TODO(xhwang): This may not work on Windows. If so, the caller should load
147 // the CDM explicitly and pass the CDM |library| in this call.
148 VerifyHostFilesFunc verify_host_files_func =
149 reinterpret_cast<VerifyHostFilesFunc>(
150 base::GetFunctionPointerFromNativeLibrary(library,
151 kVerifyHostFilesFuncName));
152 if (!verify_host_files_func) {
153 LOG(ERROR) << "Function " << kVerifyHostFilesFuncName << " not found.";
154 CloseAllFiles();
155 return;
156 }
157
158 std::vector<cdm::CdmHostFile> cdm_host_files;
159 if (TakePlatformFiles(cdm_adapter_path, &cdm_host_files))
Greg K 2017/01/09 21:45:14 I'm not sure what's going on here, so a comment mi
xhwang 2017/01/12 20:15:02 Will do.
xhwang 2017/01/18 06:03:58 Done.
160 verify_host_files_func(cdm_host_files.data(), cdm_host_files.size());
161
162 // Close all files not passed to the CDM.
163 CloseAllFiles();
164 }
165
166 #if defined(POSIX_WITH_ZYGOTE)
167 bool CdmHostFiles::OpenFilesForAllRegisteredCdms() {
168 std::vector<base::FilePath> cdm_adapter_paths;
169 GetRegisteredCdms(&cdm_adapter_paths);
170 if (cdm_adapter_paths.empty()) {
171 DVLOG(1) << "No CDM registered.";
172 return false;
173 }
174
175 for (auto& cdm_adapter_path : cdm_adapter_paths)
176 ignore_result(OpenCdmFiles(cdm_adapter_path));
177
178 if (cdm_specific_files_map_.empty()) {
179 DVLOG(1) << "CDM specific files cannot be opened for any registered CDM.";
180 return false;
181 }
182
183 return OpenCommonFiles();
184 }
185 #endif
186
187 bool CdmHostFiles::OpenFiles(const base::FilePath& cdm_adapter_path) {
188 if (!OpenCdmFiles(cdm_adapter_path))
189 return false;
190
191 return OpenCommonFiles();
192 }
193
194 bool CdmHostFiles::OpenCommonFiles() {
195 DCHECK(common_files_.empty());
196
197 base::FilePath file_exe_path;
198 base::PathService::Get(base::FILE_EXE, &file_exe_path);
199 std::unique_ptr<CdmHostFile> file_exe = CdmHostFile::Create(file_exe_path);
200 if (!file_exe) {
201 CloseAllFiles();
202 return false;
203 }
204
205 // TODO(xhwang): Open other related files.
206
207 common_files_.push_back(std::move(file_exe));
208 return true;
209 }
210
211 bool CdmHostFiles::OpenCdmFiles(const base::FilePath& cdm_adapter_path) {
212 DCHECK(!cdm_adapter_path.empty());
213 DCHECK(!cdm_specific_files_map_.count(cdm_adapter_path));
214
215 std::unique_ptr<CdmHostFile> cdm_adapter_file =
216 CdmHostFile::Create(cdm_adapter_path);
217 if (!cdm_adapter_file)
218 return false;
219
220 std::unique_ptr<CdmHostFile> cdm_file =
221 CdmHostFile::Create(GetCdmPath(cdm_adapter_path));
222 if (!cdm_file)
223 return false;
224
225 ScopedFileVector cdm_specific_files;
226 cdm_specific_files.push_back(std::move(cdm_adapter_file));
227 cdm_specific_files.push_back(std::move(cdm_file));
228
229 cdm_specific_files_map_[cdm_adapter_path] = std::move(cdm_specific_files);
230 return true;
231 }
232
233 bool CdmHostFiles::TakePlatformFiles(
234 const base::FilePath& cdm_adapter_path,
235 std::vector<cdm::CdmHostFile>* cdm_host_files) {
236 DCHECK(cdm_host_files->empty());
237
238 DCHECK(!common_files_.empty());
239
240 // Check whether CDM specific files exist.
241 const auto& iter = cdm_specific_files_map_.find(cdm_adapter_path);
242 if (iter == cdm_specific_files_map_.end()) {
243 // This could happen on Linux where CDM files fail to open for Foo CDM, but
244 // now we hit Bar CDM.
245 LOG(ERROR) << "No CDM specific files for " << cdm_adapter_path.value();
246 CloseAllFiles();
247 return false;
248 }
249
250 const ScopedFileVector& cdm_specific_files = iter->second;
251
252 // Populate an array of cdm::CdmHostFile.
253 for (const auto& file : common_files_)
254 cdm_host_files->push_back(file->TakePlatformFile());
255
256 for (const auto& file : cdm_specific_files)
257 cdm_host_files->push_back(file->TakePlatformFile());
258
259 return true;
260 }
261
262 void CdmHostFiles::CloseAllFiles() {
263 common_files_.clear();
264 cdm_specific_files_map_.clear();
265 }
266
267 // Question(xhwang): Any better way to check whether a plugin is a CDM? Maybe
268 // when we register the plugin we can set some flag explicitly?
269 bool IsCdm(const base::FilePath& cdm_adapter_path) {
270 return !GetCdmPath(cdm_adapter_path).empty();
271 }
272
273 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698