OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/browser/media/cdm/browser_cdm_manager.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <memory> | |
10 #include <string> | |
11 #include <utility> | |
12 | |
13 #include "base/bind.h" | |
14 #include "base/bind_helpers.h" | |
15 #include "base/lazy_instance.h" | |
16 #include "base/task_runner.h" | |
17 #include "build/build_config.h" | |
18 #include "content/public/browser/browser_context.h" | |
19 #include "content/public/browser/browser_thread.h" | |
20 #include "content/public/browser/content_browser_client.h" | |
21 #include "content/public/browser/permission_manager.h" | |
22 #include "content/public/browser/permission_type.h" | |
23 #include "content/public/browser/render_frame_host.h" | |
24 #include "content/public/browser/render_process_host.h" | |
25 #include "content/public/browser/render_process_host_observer.h" | |
26 #include "content/public/browser/storage_partition.h" | |
27 #include "content/public/browser/web_contents.h" | |
28 #include "media/base/cdm_config.h" | |
29 #include "media/base/cdm_factory.h" | |
30 #include "media/base/cdm_promise.h" | |
31 #include "media/base/limits.h" | |
32 | |
33 #if defined(OS_ANDROID) | |
34 #include "content/public/browser/android/provision_fetcher_factory.h" | |
35 #include "content/public/common/renderer_preferences.h" | |
36 #include "media/base/android/android_cdm_factory.h" | |
37 #endif | |
38 | |
39 namespace content { | |
40 | |
41 using media::MediaKeys; | |
42 | |
43 namespace { | |
44 | |
45 #if defined(OS_ANDROID) | |
46 // Android only supports 128-bit key IDs. | |
47 const size_t kAndroidKeyIdBytes = 128 / 8; | |
48 #endif | |
49 | |
50 // The ID used in this class is a concatenation of |render_frame_id| and | |
51 // |cdm_id|, i.e. (render_frame_id << 32) + cdm_id. | |
52 | |
53 uint64_t GetId(int render_frame_id, int cdm_id) { | |
54 return (static_cast<uint64_t>(render_frame_id) << 32) + | |
55 static_cast<uint64_t>(cdm_id); | |
56 } | |
57 | |
58 bool IdBelongsToFrame(uint64_t id, int render_frame_id) { | |
59 return (id >> 32) == static_cast<uint64_t>(render_frame_id); | |
60 } | |
61 | |
62 // media::CdmPromiseTemplate implementation backed by a BrowserCdmManager. | |
63 template <typename... T> | |
64 class CdmPromiseInternal : public media::CdmPromiseTemplate<T...> { | |
65 public: | |
66 CdmPromiseInternal(const base::WeakPtr<BrowserCdmManager>& manager, | |
67 int render_frame_id, | |
68 int cdm_id, | |
69 uint32_t promise_id) | |
70 : manager_(manager), | |
71 render_frame_id_(render_frame_id), | |
72 cdm_id_(cdm_id), | |
73 promise_id_(promise_id) { | |
74 DCHECK(manager_); | |
75 } | |
76 | |
77 ~CdmPromiseInternal() final { | |
78 if (!IsPromiseSettled()) | |
79 RejectPromiseOnDestruction(); | |
80 } | |
81 | |
82 // CdmPromiseTemplate<> implementation. | |
83 void resolve(const T&... result) final; | |
84 | |
85 void reject(MediaKeys::Exception exception, | |
86 uint32_t system_code, | |
87 const std::string& error_message) final { | |
88 MarkPromiseSettled(); | |
89 if (manager_) { | |
90 manager_->RejectPromise(render_frame_id_, cdm_id_, promise_id_, exception, | |
91 system_code, error_message); | |
92 } | |
93 } | |
94 | |
95 private: | |
96 using media::CdmPromiseTemplate<T...>::IsPromiseSettled; | |
97 using media::CdmPromiseTemplate<T...>::MarkPromiseSettled; | |
98 using media::CdmPromiseTemplate<T...>::RejectPromiseOnDestruction; | |
99 | |
100 base::WeakPtr<BrowserCdmManager> const manager_; | |
101 const int render_frame_id_; | |
102 const int cdm_id_; | |
103 const uint32_t promise_id_; | |
104 }; | |
105 | |
106 template <> | |
107 void CdmPromiseInternal<>::resolve() { | |
108 MarkPromiseSettled(); | |
109 if (manager_) | |
110 manager_->ResolvePromise(render_frame_id_, cdm_id_, promise_id_); | |
111 } | |
112 | |
113 template <> | |
114 void CdmPromiseInternal<std::string>::resolve(const std::string& session_id) { | |
115 MarkPromiseSettled(); | |
116 if (manager_) { | |
117 manager_->ResolvePromiseWithSession(render_frame_id_, cdm_id_, promise_id_, | |
118 session_id); | |
119 } | |
120 } | |
121 | |
122 typedef CdmPromiseInternal<> SimplePromise; | |
123 typedef CdmPromiseInternal<std::string> NewSessionPromise; | |
124 | |
125 // Render process ID to BrowserCdmManager map. | |
126 typedef std::map<int, BrowserCdmManager*> BrowserCdmManagerMap; | |
127 base::LazyInstance<BrowserCdmManagerMap>::Leaky g_browser_cdm_manager_map = | |
128 LAZY_INSTANCE_INITIALIZER; | |
129 | |
130 // Keeps the BrowserCdmManager alive, and in the global map, for as long as the | |
131 // RenderProcessHost is connected to the child process. This class is a | |
132 // self-owned observer. | |
133 class BrowserCdmManagerProcessWatcher : public RenderProcessHostObserver { | |
134 public: | |
135 BrowserCdmManagerProcessWatcher( | |
136 int render_process_id, | |
137 const scoped_refptr<BrowserCdmManager>& manager) | |
138 : browser_cdm_manager_(manager) { | |
139 RenderProcessHost::FromID(render_process_id)->AddObserver(this); | |
140 CHECK(g_browser_cdm_manager_map.Get() | |
141 .insert(std::make_pair(render_process_id, manager.get())) | |
142 .second); | |
143 } | |
144 | |
145 // RenderProcessHostObserver: | |
146 void RenderProcessExited(RenderProcessHost* host, | |
147 base::TerminationStatus /* status */, | |
148 int /* exit_code */) override { | |
149 RemoveHostObserverAndDestroy(host); | |
150 } | |
151 | |
152 void RenderProcessHostDestroyed(RenderProcessHost* host) override { | |
153 RemoveHostObserverAndDestroy(host); | |
154 } | |
155 | |
156 private: | |
157 void RemoveHostObserverAndDestroy(RenderProcessHost* host) { | |
158 CHECK(g_browser_cdm_manager_map.Get().erase(host->GetID())); | |
159 host->RemoveObserver(this); | |
160 delete this; | |
161 } | |
162 | |
163 const scoped_refptr<BrowserCdmManager> browser_cdm_manager_; | |
164 }; | |
165 | |
166 } // namespace | |
167 | |
168 // static | |
169 BrowserCdmManager* BrowserCdmManager::FromProcess(int render_process_id) { | |
170 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
171 auto& map = g_browser_cdm_manager_map.Get(); | |
172 auto iterator = map.find(render_process_id); | |
173 return (iterator == map.end()) ? nullptr : iterator->second; | |
174 } | |
175 | |
176 BrowserCdmManager::BrowserCdmManager( | |
177 int render_process_id, | |
178 const scoped_refptr<base::TaskRunner>& task_runner) | |
179 : BrowserMessageFilter(CdmMsgStart), | |
180 render_process_id_(render_process_id), | |
181 task_runner_(task_runner), | |
182 weak_ptr_factory_(this) { | |
183 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_; | |
184 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
185 | |
186 new BrowserCdmManagerProcessWatcher(render_process_id, this); | |
187 | |
188 if (!task_runner_.get()) { | |
189 task_runner_ = BrowserThread::GetTaskRunnerForThread(BrowserThread::UI); | |
190 } | |
191 } | |
192 | |
193 BrowserCdmManager::~BrowserCdmManager() { | |
194 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_; | |
195 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
196 } | |
197 | |
198 // Makes sure BrowserCdmManager is always deleted on the Browser UI thread. | |
199 void BrowserCdmManager::OnDestruct() const { | |
200 DVLOG(1) << __FUNCTION__ << ": " << render_process_id_; | |
201 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
202 delete this; | |
203 } else { | |
204 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); | |
205 } | |
206 } | |
207 | |
208 base::TaskRunner* BrowserCdmManager::OverrideTaskRunnerForMessage( | |
209 const IPC::Message& message) { | |
210 // Only handles CDM messages. | |
211 if (IPC_MESSAGE_CLASS(message) != CdmMsgStart) | |
212 return NULL; | |
213 | |
214 return task_runner_.get(); | |
215 } | |
216 | |
217 bool BrowserCdmManager::OnMessageReceived(const IPC::Message& msg) { | |
218 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
219 bool handled = true; | |
220 IPC_BEGIN_MESSAGE_MAP(BrowserCdmManager, msg) | |
221 IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm) | |
222 IPC_MESSAGE_HANDLER(CdmHostMsg_SetServerCertificate, OnSetServerCertificate) | |
223 IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSessionAndGenerateRequest, | |
224 OnCreateSessionAndGenerateRequest) | |
225 IPC_MESSAGE_HANDLER(CdmHostMsg_LoadSession, OnLoadSession) | |
226 IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession) | |
227 IPC_MESSAGE_HANDLER(CdmHostMsg_CloseSession, OnCloseSession) | |
228 IPC_MESSAGE_HANDLER(CdmHostMsg_RemoveSession, OnRemoveSession) | |
229 IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm) | |
230 IPC_MESSAGE_UNHANDLED(handled = false) | |
231 IPC_END_MESSAGE_MAP() | |
232 return handled; | |
233 } | |
234 | |
235 scoped_refptr<MediaKeys> BrowserCdmManager::GetCdm(int render_frame_id, | |
236 int cdm_id) const { | |
237 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
238 const auto& iter = cdm_map_.find(GetId(render_frame_id, cdm_id)); | |
239 return iter == cdm_map_.end() ? nullptr : iter->second; | |
240 } | |
241 | |
242 void BrowserCdmManager::RenderFrameDeleted(int render_frame_id) { | |
243 if (!task_runner_->RunsTasksOnCurrentThread()) { | |
244 task_runner_->PostTask( | |
245 FROM_HERE, | |
246 base::Bind(&BrowserCdmManager::RemoveAllCdmForFrame, | |
247 this, render_frame_id)); | |
248 return; | |
249 } | |
250 RemoveAllCdmForFrame(render_frame_id); | |
251 } | |
252 | |
253 void BrowserCdmManager::ResolvePromise(int render_frame_id, | |
254 int cdm_id, | |
255 uint32_t promise_id) { | |
256 Send(new CdmMsg_ResolvePromise(render_frame_id, cdm_id, promise_id)); | |
257 } | |
258 | |
259 void BrowserCdmManager::ResolvePromiseWithSession( | |
260 int render_frame_id, | |
261 int cdm_id, | |
262 uint32_t promise_id, | |
263 const std::string& session_id) { | |
264 if (session_id.length() > media::limits::kMaxSessionIdLength) { | |
265 RejectPromise(render_frame_id, cdm_id, promise_id, | |
266 MediaKeys::INVALID_ACCESS_ERROR, 0, | |
267 "Session ID is too long."); | |
268 return; | |
269 } | |
270 | |
271 Send(new CdmMsg_ResolvePromiseWithSession(render_frame_id, cdm_id, promise_id, | |
272 session_id)); | |
273 } | |
274 | |
275 void BrowserCdmManager::RejectPromise(int render_frame_id, | |
276 int cdm_id, | |
277 uint32_t promise_id, | |
278 MediaKeys::Exception exception, | |
279 uint32_t system_code, | |
280 const std::string& error_message) { | |
281 Send(new CdmMsg_RejectPromise(render_frame_id, cdm_id, promise_id, exception, | |
282 system_code, error_message)); | |
283 } | |
284 | |
285 media::CdmFactory* BrowserCdmManager::GetCdmFactory() { | |
286 if (!cdm_factory_) { | |
287 // Create a new CdmFactory. | |
288 cdm_factory_ = GetContentClient()->browser()->CreateCdmFactory(); | |
289 | |
290 #if defined(OS_ANDROID) | |
291 if (!cdm_factory_) { | |
292 // Obtain http request context for the current render process. | |
293 net::URLRequestContextGetter* context_getter = | |
294 BrowserContext::GetDefaultStoragePartition( | |
295 RenderProcessHost::FromID(render_process_id_)-> | |
296 GetBrowserContext())->GetURLRequestContext(); | |
297 DCHECK(context_getter); | |
298 | |
299 cdm_factory_.reset(new media::AndroidCdmFactory( | |
300 base::Bind(&CreateProvisionFetcher, context_getter))); | |
301 } | |
302 #endif | |
303 } | |
304 | |
305 return cdm_factory_.get(); | |
306 } | |
307 | |
308 void BrowserCdmManager::OnSessionMessage(int render_frame_id, | |
309 int cdm_id, | |
310 const std::string& session_id, | |
311 MediaKeys::MessageType message_type, | |
312 const std::vector<uint8_t>& message) { | |
313 Send(new CdmMsg_SessionMessage(render_frame_id, cdm_id, session_id, | |
314 message_type, message)); | |
315 } | |
316 | |
317 void BrowserCdmManager::OnSessionClosed(int render_frame_id, | |
318 int cdm_id, | |
319 const std::string& session_id) { | |
320 Send(new CdmMsg_SessionClosed(render_frame_id, cdm_id, session_id)); | |
321 } | |
322 | |
323 void BrowserCdmManager::OnSessionKeysChange(int render_frame_id, | |
324 int cdm_id, | |
325 const std::string& session_id, | |
326 bool has_additional_usable_key, | |
327 media::CdmKeysInfo keys_info) { | |
328 std::vector<media::CdmKeyInformation> key_info_vector; | |
329 for (auto* key_info : keys_info) | |
330 key_info_vector.push_back(*key_info); | |
331 Send(new CdmMsg_SessionKeysChange(render_frame_id, cdm_id, session_id, | |
332 has_additional_usable_key, | |
333 key_info_vector)); | |
334 } | |
335 | |
336 void BrowserCdmManager::OnSessionExpirationUpdate( | |
337 int render_frame_id, | |
338 int cdm_id, | |
339 const std::string& session_id, | |
340 const base::Time& new_expiry_time) { | |
341 Send(new CdmMsg_SessionExpirationUpdate(render_frame_id, cdm_id, session_id, | |
342 new_expiry_time)); | |
343 } | |
344 | |
345 // Use a weak pointer here instead of |this| to avoid circular references. | |
346 #define BROWSER_CDM_MANAGER_CB(func, ...) \ | |
347 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ | |
348 render_frame_id, cdm_id, ##__VA_ARGS__) | |
349 | |
350 void BrowserCdmManager::OnInitializeCdm( | |
351 int render_frame_id, | |
352 int cdm_id, | |
353 uint32_t promise_id, | |
354 const CdmHostMsg_InitializeCdm_Params& params) { | |
355 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
356 DCHECK(!GetCdm(render_frame_id, cdm_id)); | |
357 | |
358 std::unique_ptr<SimplePromise> promise(new SimplePromise( | |
359 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
360 | |
361 if (params.key_system.size() > media::limits::kMaxKeySystemLength) { | |
362 NOTREACHED() << "Invalid key system: " << params.key_system; | |
363 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Invalid key system."); | |
364 return; | |
365 } | |
366 | |
367 if (!GetCdmFactory()) { | |
368 NOTREACHED() << "CDM not supported."; | |
369 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "CDM not supported."); | |
370 return; | |
371 } | |
372 | |
373 // The render process makes sure |allow_distinctive_identifier| and | |
374 // |allow_persistent_state| are true. See RenderCdmFactory::Create(). | |
375 // TODO(xhwang): Pass |allow_distinctive_identifier| and | |
376 // |allow_persistent_state| from the render process. | |
377 media::CdmConfig cdm_config; | |
378 cdm_config.allow_distinctive_identifier = true; | |
379 cdm_config.allow_persistent_state = true; | |
380 cdm_config.use_hw_secure_codecs = params.use_hw_secure_codecs; | |
381 | |
382 GetCdmFactory()->Create( | |
383 params.key_system, params.security_origin, cdm_config, | |
384 BROWSER_CDM_MANAGER_CB(OnSessionMessage), | |
385 BROWSER_CDM_MANAGER_CB(OnSessionClosed), | |
386 BROWSER_CDM_MANAGER_CB(OnSessionKeysChange), | |
387 BROWSER_CDM_MANAGER_CB(OnSessionExpirationUpdate), | |
388 BROWSER_CDM_MANAGER_CB(OnCdmCreated, params.security_origin, | |
389 base::Passed(&promise))); | |
390 } | |
391 | |
392 void BrowserCdmManager::OnSetServerCertificate( | |
393 int render_frame_id, | |
394 int cdm_id, | |
395 uint32_t promise_id, | |
396 const std::vector<uint8_t>& certificate) { | |
397 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
398 | |
399 std::unique_ptr<SimplePromise> promise(new SimplePromise( | |
400 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
401 | |
402 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
403 if (!cdm) { | |
404 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
405 return; | |
406 } | |
407 | |
408 if (certificate.empty()) { | |
409 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate."); | |
410 return; | |
411 } | |
412 | |
413 cdm->SetServerCertificate(certificate, std::move(promise)); | |
414 } | |
415 | |
416 void BrowserCdmManager::OnCreateSessionAndGenerateRequest( | |
417 const CdmHostMsg_CreateSessionAndGenerateRequest_Params& params) { | |
418 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
419 | |
420 int render_frame_id = params.render_frame_id; | |
421 int cdm_id = params.cdm_id; | |
422 const std::vector<uint8_t>& init_data = params.init_data; | |
423 std::unique_ptr<NewSessionPromise> promise( | |
424 new NewSessionPromise(weak_ptr_factory_.GetWeakPtr(), render_frame_id, | |
425 cdm_id, params.promise_id)); | |
426 | |
427 if (init_data.size() > media::limits::kMaxInitDataLength) { | |
428 LOG(WARNING) << "InitData for ID: " << cdm_id | |
429 << " too long: " << init_data.size(); | |
430 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long."); | |
431 return; | |
432 } | |
433 #if defined(OS_ANDROID) | |
434 // 'webm' initData is a single key ID. On Android the length is restricted. | |
435 if (params.init_data_type == INIT_DATA_TYPE_WEBM && | |
436 init_data.size() != kAndroidKeyIdBytes) { | |
437 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, | |
438 "'webm' initData is not the correct length."); | |
439 return; | |
440 } | |
441 #endif | |
442 | |
443 media::EmeInitDataType eme_init_data_type; | |
444 switch (params.init_data_type) { | |
445 case INIT_DATA_TYPE_WEBM: | |
446 eme_init_data_type = media::EmeInitDataType::WEBM; | |
447 break; | |
448 #if defined(USE_PROPRIETARY_CODECS) | |
449 case INIT_DATA_TYPE_CENC: | |
450 eme_init_data_type = media::EmeInitDataType::CENC; | |
451 break; | |
452 #endif | |
453 default: | |
454 NOTREACHED(); | |
455 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, | |
456 "Invalid init data type."); | |
457 return; | |
458 } | |
459 | |
460 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
461 if (!cdm) { | |
462 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id; | |
463 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
464 return; | |
465 } | |
466 | |
467 CheckPermissionStatus( | |
468 render_frame_id, cdm_id, | |
469 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted, | |
470 this, render_frame_id, cdm_id, params.session_type, | |
471 eme_init_data_type, init_data, base::Passed(&promise))); | |
472 } | |
473 | |
474 void BrowserCdmManager::OnLoadSession( | |
475 int render_frame_id, | |
476 int cdm_id, | |
477 uint32_t promise_id, | |
478 media::MediaKeys::SessionType session_type, | |
479 const std::string& session_id) { | |
480 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
481 | |
482 std::unique_ptr<NewSessionPromise> promise(new NewSessionPromise( | |
483 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
484 | |
485 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
486 if (!cdm) { | |
487 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id; | |
488 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
489 return; | |
490 } | |
491 | |
492 CheckPermissionStatus( | |
493 render_frame_id, cdm_id, | |
494 base::Bind(&BrowserCdmManager::LoadSessionIfPermitted, | |
495 this, render_frame_id, cdm_id, session_type, | |
496 session_id, base::Passed(&promise))); | |
497 } | |
498 | |
499 void BrowserCdmManager::OnUpdateSession(int render_frame_id, | |
500 int cdm_id, | |
501 uint32_t promise_id, | |
502 const std::string& session_id, | |
503 const std::vector<uint8_t>& response) { | |
504 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
505 | |
506 std::unique_ptr<SimplePromise> promise(new SimplePromise( | |
507 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
508 | |
509 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
510 if (!cdm) { | |
511 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
512 return; | |
513 } | |
514 | |
515 if (response.size() > media::limits::kMaxSessionResponseLength) { | |
516 LOG(WARNING) << "Response for ID " << cdm_id | |
517 << " is too long: " << response.size(); | |
518 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); | |
519 return; | |
520 } | |
521 | |
522 if (response.empty()) { | |
523 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); | |
524 return; | |
525 } | |
526 | |
527 cdm->UpdateSession(session_id, response, std::move(promise)); | |
528 } | |
529 | |
530 void BrowserCdmManager::OnCloseSession(int render_frame_id, | |
531 int cdm_id, | |
532 uint32_t promise_id, | |
533 const std::string& session_id) { | |
534 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
535 | |
536 std::unique_ptr<SimplePromise> promise(new SimplePromise( | |
537 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
538 | |
539 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
540 if (!cdm) { | |
541 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
542 return; | |
543 } | |
544 | |
545 cdm->CloseSession(session_id, std::move(promise)); | |
546 } | |
547 | |
548 void BrowserCdmManager::OnRemoveSession(int render_frame_id, | |
549 int cdm_id, | |
550 uint32_t promise_id, | |
551 const std::string& session_id) { | |
552 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
553 | |
554 std::unique_ptr<SimplePromise> promise(new SimplePromise( | |
555 weak_ptr_factory_.GetWeakPtr(), render_frame_id, cdm_id, promise_id)); | |
556 | |
557 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
558 if (!cdm) { | |
559 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
560 return; | |
561 } | |
562 | |
563 cdm->RemoveSession(session_id, std::move(promise)); | |
564 } | |
565 | |
566 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { | |
567 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
568 RemoveCdm(GetId(render_frame_id, cdm_id)); | |
569 } | |
570 | |
571 void BrowserCdmManager::OnCdmCreated( | |
572 int render_frame_id, | |
573 int cdm_id, | |
574 const GURL& security_origin, | |
575 std::unique_ptr<media::SimpleCdmPromise> promise, | |
576 const scoped_refptr<media::MediaKeys>& cdm, | |
577 const std::string& error_message) { | |
578 if (!cdm) { | |
579 DVLOG(1) << "Failed to create CDM: " << error_message; | |
580 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, error_message); | |
581 return; | |
582 } | |
583 | |
584 uint64_t id = GetId(render_frame_id, cdm_id); | |
585 cdm_map_[id] = cdm; | |
586 cdm_security_origin_map_[id] = security_origin; | |
587 promise->resolve(); | |
588 } | |
589 | |
590 void BrowserCdmManager::RemoveAllCdmForFrame(int render_frame_id) { | |
591 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
592 | |
593 std::vector<uint64_t> ids_to_remove; | |
594 for (const auto& entry : cdm_map_) { | |
595 if (IdBelongsToFrame(entry.first, render_frame_id)) | |
596 ids_to_remove.push_back(entry.first); | |
597 } | |
598 | |
599 for (const auto& id_to_remove : ids_to_remove) | |
600 RemoveCdm(id_to_remove); | |
601 } | |
602 | |
603 void BrowserCdmManager::RemoveCdm(uint64_t id) { | |
604 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
605 | |
606 cdm_map_.erase(id); | |
607 cdm_security_origin_map_.erase(id); | |
608 } | |
609 | |
610 void BrowserCdmManager::CheckPermissionStatus( | |
611 int render_frame_id, | |
612 int cdm_id, | |
613 const PermissionStatusCB& permission_status_cb) { | |
614 // Always called on |task_runner_|, which may not be on the UI thread. | |
615 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
616 | |
617 GURL security_origin; | |
618 std::map<uint64_t, GURL>::const_iterator iter = | |
619 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); | |
620 DCHECK(iter != cdm_security_origin_map_.end()); | |
621 if (iter != cdm_security_origin_map_.end()) | |
622 security_origin = iter->second; | |
623 | |
624 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
625 BrowserThread::PostTask( | |
626 BrowserThread::UI, FROM_HERE, | |
627 base::Bind(&BrowserCdmManager::CheckPermissionStatusOnUIThread, this, | |
628 render_frame_id, security_origin, permission_status_cb)); | |
629 } else { | |
630 CheckPermissionStatusOnUIThread(render_frame_id, security_origin, | |
631 permission_status_cb); | |
632 } | |
633 } | |
634 | |
635 // Note: This function runs on the UI thread, which may be different from | |
636 // |task_runner_|. Be careful about thread safety! | |
637 void BrowserCdmManager::CheckPermissionStatusOnUIThread( | |
638 int render_frame_id, | |
639 const GURL& security_origin, | |
640 const base::Callback<void(bool)>& permission_status_cb) { | |
641 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
642 | |
643 RenderFrameHost* rfh = | |
644 RenderFrameHost::FromID(render_process_id_, render_frame_id); | |
645 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); | |
646 PermissionManager* permission_manager = | |
647 web_contents->GetBrowserContext()->GetPermissionManager(); | |
648 if (!permission_manager) { | |
649 permission_status_cb.Run(false); | |
650 return; | |
651 } | |
652 | |
653 blink::mojom::PermissionStatus permission_status = | |
654 permission_manager->GetPermissionStatus( | |
655 PermissionType::PROTECTED_MEDIA_IDENTIFIER, security_origin, | |
656 web_contents->GetLastCommittedURL().GetOrigin()); | |
657 | |
658 bool allowed = (permission_status == blink::mojom::PermissionStatus::GRANTED); | |
659 if (!task_runner_->RunsTasksOnCurrentThread()) { | |
660 task_runner_->PostTask(FROM_HERE, | |
661 base::Bind(permission_status_cb, allowed)); | |
662 } else { | |
663 permission_status_cb.Run(allowed); | |
664 } | |
665 } | |
666 | |
667 void BrowserCdmManager::CreateSessionAndGenerateRequestIfPermitted( | |
668 int render_frame_id, | |
669 int cdm_id, | |
670 media::MediaKeys::SessionType session_type, | |
671 media::EmeInitDataType init_data_type, | |
672 const std::vector<uint8_t>& init_data, | |
673 std::unique_ptr<media::NewSessionCdmPromise> promise, | |
674 bool permission_was_allowed) { | |
675 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
676 | |
677 if (!permission_was_allowed) { | |
678 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); | |
679 return; | |
680 } | |
681 | |
682 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
683 if (!cdm) { | |
684 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
685 return; | |
686 } | |
687 | |
688 cdm->CreateSessionAndGenerateRequest(session_type, init_data_type, init_data, | |
689 std::move(promise)); | |
690 } | |
691 | |
692 void BrowserCdmManager::LoadSessionIfPermitted( | |
693 int render_frame_id, | |
694 int cdm_id, | |
695 media::MediaKeys::SessionType session_type, | |
696 const std::string& session_id, | |
697 std::unique_ptr<media::NewSessionCdmPromise> promise, | |
698 bool permission_was_allowed) { | |
699 DCHECK_NE(media::MediaKeys::SessionType::TEMPORARY_SESSION, session_type); | |
700 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | |
701 | |
702 if (!permission_was_allowed) { | |
703 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); | |
704 return; | |
705 } | |
706 | |
707 scoped_refptr<MediaKeys> cdm = GetCdm(render_frame_id, cdm_id); | |
708 if (!cdm) { | |
709 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); | |
710 return; | |
711 } | |
712 | |
713 cdm->LoadSession(session_type, session_id, std::move(promise)); | |
714 } | |
715 | |
716 } // namespace content | |
OLD | NEW |