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

Side by Side Diff: content/browser/media/cdm/browser_cdm_manager.cc

Issue 1013913002: media: Fix permission request/check for EME on Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months 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
« no previous file with comments | « content/browser/media/cdm/browser_cdm_manager.h ('k') | media/cdm/proxy_decryptor.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/media/cdm/browser_cdm_manager.h" 5 #include "content/browser/media/cdm/browser_cdm_manager.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 } 304 }
305 305
306 AddCdm(render_frame_id, cdm_id, key_system, security_origin); 306 AddCdm(render_frame_id, cdm_id, key_system, security_origin);
307 } 307 }
308 308
309 void BrowserCdmManager::OnSetServerCertificate( 309 void BrowserCdmManager::OnSetServerCertificate(
310 int render_frame_id, 310 int render_frame_id,
311 int cdm_id, 311 int cdm_id,
312 uint32_t promise_id, 312 uint32_t promise_id,
313 const std::vector<uint8_t>& certificate) { 313 const std::vector<uint8_t>& certificate) {
314 DCHECK(task_runner_->RunsTasksOnCurrentThread());
315
314 scoped_ptr<SimplePromise> promise( 316 scoped_ptr<SimplePromise> promise(
315 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); 317 new SimplePromise(this, render_frame_id, cdm_id, promise_id));
316 318
317 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); 319 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
318 if (!cdm) { 320 if (!cdm) {
319 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 321 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
320 return; 322 return;
321 } 323 }
322 324
323 if (certificate.empty()) { 325 if (certificate.empty()) {
324 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate."); 326 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Empty certificate.");
325 return; 327 return;
326 } 328 }
327 329
328 cdm->SetServerCertificate(&certificate[0], certificate.size(), 330 cdm->SetServerCertificate(&certificate[0], certificate.size(),
329 promise.Pass()); 331 promise.Pass());
330 } 332 }
331 333
332 void BrowserCdmManager::OnCreateSessionAndGenerateRequest( 334 void BrowserCdmManager::OnCreateSessionAndGenerateRequest(
333 int render_frame_id, 335 int render_frame_id,
334 int cdm_id, 336 int cdm_id,
335 uint32_t promise_id, 337 uint32_t promise_id,
336 CdmHostMsg_CreateSession_InitDataType init_data_type, 338 CdmHostMsg_CreateSession_InitDataType init_data_type,
337 const std::vector<uint8>& init_data) { 339 const std::vector<uint8>& init_data) {
340 DCHECK(task_runner_->RunsTasksOnCurrentThread());
341
338 scoped_ptr<NewSessionPromise> promise( 342 scoped_ptr<NewSessionPromise> promise(
339 new NewSessionPromise(this, render_frame_id, cdm_id, promise_id)); 343 new NewSessionPromise(this, render_frame_id, cdm_id, promise_id));
340 344
341 if (init_data.size() > kMaxInitDataLength) { 345 if (init_data.size() > kMaxInitDataLength) {
342 LOG(WARNING) << "InitData for ID: " << cdm_id 346 LOG(WARNING) << "InitData for ID: " << cdm_id
343 << " too long: " << init_data.size(); 347 << " too long: " << init_data.size();
344 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long."); 348 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Init data too long.");
345 return; 349 return;
346 } 350 }
347 351
(...skipping 10 matching lines...) Expand all
358 default: 362 default:
359 NOTREACHED(); 363 NOTREACHED();
360 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, 364 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0,
361 "Invalid init data type."); 365 "Invalid init data type.");
362 return; 366 return;
363 } 367 }
364 368
365 #if defined(OS_ANDROID) 369 #if defined(OS_ANDROID)
366 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 370 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
367 switches::kDisableInfobarForProtectedMediaIdentifier)) { 371 switches::kDisableInfobarForProtectedMediaIdentifier)) {
368 GenerateRequestIfPermitted( 372 CreateSessionAndGenerateRequest(render_frame_id, cdm_id, eme_init_data_type,
369 render_frame_id, cdm_id, eme_init_data_type, 373 init_data, promise.Pass(),
370 init_data, promise.Pass(), PERMISSION_STATUS_GRANTED); 374 PERMISSION_STATUS_GRANTED);
371 return; 375 return;
372 } 376 }
373 #endif 377 #endif
374 378
375 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); 379 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
376 if (!cdm) { 380 if (!cdm) {
377 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id; 381 DLOG(WARNING) << "No CDM found for: " << render_frame_id << ", " << cdm_id;
378 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 382 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
379 return; 383 return;
380 } 384 }
381 385
382 std::map<uint64, GURL>::const_iterator iter = 386 std::map<uint64, GURL>::const_iterator iter =
383 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id)); 387 cdm_security_origin_map_.find(GetId(render_frame_id, cdm_id));
384 if (iter == cdm_security_origin_map_.end()) { 388 if (iter == cdm_security_origin_map_.end()) {
385 NOTREACHED(); 389 NOTREACHED();
386 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 390 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "Origin not found.");
387 return; 391 return;
388 } 392 }
389 GURL security_origin = iter->second; 393 GURL security_origin = iter->second;
390 394
391 RequestSessionPermission(render_frame_id, security_origin, cdm_id, 395 CheckPermissionStatus(render_frame_id, security_origin, cdm_id,
392 eme_init_data_type, init_data, promise.Pass()); 396 eme_init_data_type, init_data, promise.Pass());
393 } 397 }
394 398
395 void BrowserCdmManager::OnUpdateSession(int render_frame_id, 399 void BrowserCdmManager::OnUpdateSession(int render_frame_id,
396 int cdm_id, 400 int cdm_id,
397 uint32_t promise_id, 401 uint32_t promise_id,
398 const std::string& session_id, 402 const std::string& session_id,
399 const std::vector<uint8>& response) { 403 const std::vector<uint8>& response) {
404 DCHECK(task_runner_->RunsTasksOnCurrentThread());
405
400 scoped_ptr<SimplePromise> promise( 406 scoped_ptr<SimplePromise> promise(
401 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); 407 new SimplePromise(this, render_frame_id, cdm_id, promise_id));
402 408
403 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); 409 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
404 if (!cdm) { 410 if (!cdm) {
405 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 411 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
406 return; 412 return;
407 } 413 }
408 414
409 if (response.size() > kMaxSessionResponseLength) { 415 if (response.size() > kMaxSessionResponseLength) {
410 LOG(WARNING) << "Response for ID " << cdm_id 416 LOG(WARNING) << "Response for ID " << cdm_id
411 << " is too long: " << response.size(); 417 << " is too long: " << response.size();
412 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long."); 418 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response too long.");
413 return; 419 return;
414 } 420 }
415 421
416 if (response.empty()) { 422 if (response.empty()) {
417 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty."); 423 promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, "Response is empty.");
418 return; 424 return;
419 } 425 }
420 426
421 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass()); 427 cdm->UpdateSession(session_id, &response[0], response.size(), promise.Pass());
422 } 428 }
423 429
424 void BrowserCdmManager::OnCloseSession(int render_frame_id, 430 void BrowserCdmManager::OnCloseSession(int render_frame_id,
425 int cdm_id, 431 int cdm_id,
426 uint32_t promise_id, 432 uint32_t promise_id,
427 const std::string& session_id) { 433 const std::string& session_id) {
434 DCHECK(task_runner_->RunsTasksOnCurrentThread());
435
428 scoped_ptr<SimplePromise> promise( 436 scoped_ptr<SimplePromise> promise(
429 new SimplePromise(this, render_frame_id, cdm_id, promise_id)); 437 new SimplePromise(this, render_frame_id, cdm_id, promise_id));
430 438
431 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); 439 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
432 if (!cdm) { 440 if (!cdm) {
433 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 441 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
434 return; 442 return;
435 } 443 }
436 444
437 cdm->CloseSession(session_id, promise.Pass()); 445 cdm->CloseSession(session_id, promise.Pass());
438 } 446 }
439 447
440 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) { 448 void BrowserCdmManager::OnDestroyCdm(int render_frame_id, int cdm_id) {
449 DCHECK(task_runner_->RunsTasksOnCurrentThread());
441 RemoveCdm(GetId(render_frame_id, cdm_id)); 450 RemoveCdm(GetId(render_frame_id, cdm_id));
442 } 451 }
443 452
444 // Use a weak pointer here instead of |this| to avoid circular references. 453 // Use a weak pointer here instead of |this| to avoid circular references.
445 #define BROWSER_CDM_MANAGER_CB(func) \ 454 #define BROWSER_CDM_MANAGER_CB(func) \
446 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \ 455 base::Bind(&BrowserCdmManager::func, weak_ptr_factory_.GetWeakPtr(), \
447 render_frame_id, cdm_id) 456 render_frame_id, cdm_id)
448 457
449 void BrowserCdmManager::AddCdm(int render_frame_id, 458 void BrowserCdmManager::AddCdm(int render_frame_id,
450 int cdm_id, 459 int cdm_id,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 492
484 for (size_t i = 0; i < ids_to_remove.size(); ++i) 493 for (size_t i = 0; i < ids_to_remove.size(); ++i)
485 RemoveCdm(ids_to_remove[i]); 494 RemoveCdm(ids_to_remove[i]);
486 } 495 }
487 496
488 void BrowserCdmManager::RemoveCdm(uint64 id) { 497 void BrowserCdmManager::RemoveCdm(uint64 id) {
489 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 498 DCHECK(task_runner_->RunsTasksOnCurrentThread());
490 499
491 cdm_map_.erase(id); 500 cdm_map_.erase(id);
492 cdm_security_origin_map_.erase(id); 501 cdm_security_origin_map_.erase(id);
493 if (cdm_cancel_permission_map_.count(id)) {
494 cdm_cancel_permission_map_[id].Run();
495 cdm_cancel_permission_map_.erase(id);
496 }
497 } 502 }
498 503
499 void BrowserCdmManager::RequestSessionPermission( 504 void BrowserCdmManager::CheckPermissionStatus(
500 int render_frame_id, 505 int render_frame_id,
501 const GURL& security_origin, 506 const GURL& security_origin,
502 int cdm_id, 507 int cdm_id,
503 media::EmeInitDataType init_data_type, 508 media::EmeInitDataType init_data_type,
504 const std::vector<uint8>& init_data, 509 const std::vector<uint8>& init_data,
505 scoped_ptr<media::NewSessionCdmPromise> promise) { 510 scoped_ptr<media::NewSessionCdmPromise> promise) {
511 DCHECK(task_runner_->RunsTasksOnCurrentThread());
ddorwin 2015/03/16 23:58:28 This seems inconsistent with the need for line 514
xhwang 2015/03/17 01:25:22 |task_runner_| is not always on the UI thread. Add
512
513 // RenderFrameHost::FromID() can only be called from the UI thread.
506 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 514 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
507 BrowserThread::PostTask( 515 BrowserThread::PostTask(
508 BrowserThread::UI, FROM_HERE, 516 BrowserThread::UI, FROM_HERE,
509 base::Bind(&BrowserCdmManager::RequestSessionPermission, this, 517 base::Bind(&BrowserCdmManager::CheckPermissionStatus, this,
510 render_frame_id, security_origin, cdm_id, init_data_type, 518 render_frame_id, security_origin, cdm_id, init_data_type,
511 init_data, base::Passed(&promise))); 519 init_data, base::Passed(&promise)));
512 return; 520 return;
513 } 521 }
514 522
523 // Note: This part of code may not run on the |task_runner_|. Be careful
524 // about thread safty!
525
515 RenderFrameHost* rfh = 526 RenderFrameHost* rfh =
516 RenderFrameHost::FromID(render_process_id_, render_frame_id); 527 RenderFrameHost::FromID(render_process_id_, render_frame_id);
517 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh); 528 WebContents* web_contents = WebContents::FromRenderFrameHost(rfh);
518 DCHECK(web_contents); 529
519 GetContentClient()->browser()->RequestPermission( 530 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
520 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER, web_contents, 531
521 0, // bridge id 532 PermissionStatus permission_status =
522 security_origin, 533 GetContentClient()->browser()->GetPermissionStatus(
523 // Only implemented for Android infobars which do not support 534 content::PERMISSION_PROTECTED_MEDIA_IDENTIFIER,
524 // user gestures. 535 web_contents->GetBrowserContext(), security_origin, embedding_origin);
525 true, base::Bind(&BrowserCdmManager::GenerateRequestIfPermitted, this, 536
526 render_frame_id, cdm_id, init_data_type, init_data, 537 CreateSessionAndGenerateRequest(render_frame_id, cdm_id, init_data_type,
ddorwin 2015/03/16 23:58:28 It seems odd to do this inside CheckPermissionStat
xhwang 2015/03/17 01:25:22 Good point. Updated.
527 base::Passed(&promise))); 538 init_data, promise.Pass(), permission_status);
528 } 539 }
529 540
530 void BrowserCdmManager::GenerateRequestIfPermitted( 541 void BrowserCdmManager::CreateSessionAndGenerateRequest(
531 int render_frame_id, 542 int render_frame_id,
532 int cdm_id, 543 int cdm_id,
533 media::EmeInitDataType init_data_type, 544 media::EmeInitDataType init_data_type,
534 const std::vector<uint8>& init_data, 545 const std::vector<uint8>& init_data,
535 scoped_ptr<media::NewSessionCdmPromise> promise, 546 scoped_ptr<media::NewSessionCdmPromise> promise,
536 PermissionStatus permission) { 547 PermissionStatus permission_status) {
537 cdm_cancel_permission_map_.erase(GetId(render_frame_id, cdm_id)); 548 // Make sure cdm->CreateSessionAndGenerateRequest() is called on the
538 if (permission != PERMISSION_STATUS_GRANTED) { 549 // |task_runner_|.
550 if (!task_runner_->RunsTasksOnCurrentThread()) {
551 task_runner_->PostTask(
552 FROM_HERE,
553 base::Bind(&BrowserCdmManager::CreateSessionAndGenerateRequest, this,
554 render_frame_id, cdm_id, init_data_type, init_data,
555 base::Passed(&promise), permission_status));
556 return;
557 }
558
559 if (permission_status != PERMISSION_STATUS_GRANTED) {
ddorwin 2015/03/16 23:58:28 Why do we do this here? Probably because GenerateR
xhwang 2015/03/17 01:25:22 Done.
539 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied."); 560 promise->reject(MediaKeys::NOT_SUPPORTED_ERROR, 0, "Permission denied.");
540 return; 561 return;
541 } 562 }
542 563
543 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id); 564 BrowserCdm* cdm = GetCdm(render_frame_id, cdm_id);
544 if (!cdm) { 565 if (!cdm) {
545 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found."); 566 promise->reject(MediaKeys::INVALID_STATE_ERROR, 0, "CDM not found.");
546 return; 567 return;
547 } 568 }
548 569
(...skipping 15 matching lines...) Expand all
564 } 585 }
565 586
566 // Only the temporary session type is supported in browser CDM path. 587 // Only the temporary session type is supported in browser CDM path.
567 // TODO(xhwang): Add SessionType support if needed. 588 // TODO(xhwang): Add SessionType support if needed.
568 cdm->CreateSessionAndGenerateRequest(media::MediaKeys::TEMPORARY_SESSION, 589 cdm->CreateSessionAndGenerateRequest(media::MediaKeys::TEMPORARY_SESSION,
569 init_data_type_string, &init_data[0], 590 init_data_type_string, &init_data[0],
570 init_data.size(), promise.Pass()); 591 init_data.size(), promise.Pass());
571 } 592 }
572 593
573 } // namespace content 594 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/media/cdm/browser_cdm_manager.h ('k') | media/cdm/proxy_decryptor.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698