Commit bf166056 authored by yucliu's avatar yucliu Committed by Commit Bot

[Clank] Load origin id before create MediaDrmBridge

Async Create MediaDrmBridge. When persistent license support is enabled,
we need to load origin id from persistent storage before create
MediaDrmStorage.

BUG=493521
TEST=Test page, MediaDrmBridgeTest

Review-Url: https://codereview.chromium.org/2823513002
Cr-Commit-Position: refs/heads/master@{#488784}
parent 7a2ac6c7
...@@ -94,19 +94,24 @@ void MediaDrmCredentialManager::ResetCredentialsInternal( ...@@ -94,19 +94,24 @@ void MediaDrmCredentialManager::ResetCredentialsInternal(
base::Bind(&content::CreateProvisionFetcher, base::Bind(&content::CreateProvisionFetcher,
g_browser_process->system_request_context()); g_browser_process->system_request_context());
ResetCredentialsCB reset_credentials_cb = media::MediaDrmBridge::CreateWithoutSessionSupport(
kWidevineKeySystem, security_level, create_fetcher_cb,
base::BindOnce(
&MediaDrmCredentialManager::OnMediaDrmCreated, base::Unretained(this),
base::Bind(&MediaDrmCredentialManager::OnResetCredentialsCompleted, base::Bind(&MediaDrmCredentialManager::OnResetCredentialsCompleted,
base::Unretained(this), security_level); base::Unretained(this), security_level)));
}
media_drm_bridge_ = media::MediaDrmBridge::CreateWithoutSessionSupport(
kWidevineKeySystem, security_level, create_fetcher_cb);
void MediaDrmCredentialManager::OnMediaDrmCreated(
const ResetCredentialsCB& reset_credentials_cb,
scoped_refptr<media::MediaDrmBridge> cdm) {
// No need to reset credentials for unsupported |security_level|. // No need to reset credentials for unsupported |security_level|.
if (!media_drm_bridge_) { if (!cdm) {
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(reset_credentials_cb, true)); FROM_HERE, base::Bind(reset_credentials_cb, true));
return; return;
} }
media_drm_bridge_ = std::move(cdm);
media_drm_bridge_->ResetDeviceCredentials(reset_credentials_cb); media_drm_bridge_->ResetDeviceCredentials(reset_credentials_cb);
} }
...@@ -53,6 +53,9 @@ class MediaDrmCredentialManager { ...@@ -53,6 +53,9 @@ class MediaDrmCredentialManager {
// returned asynchronously in OnResetCredentialsCompleted() function. // returned asynchronously in OnResetCredentialsCompleted() function.
void ResetCredentialsInternal(SecurityLevel security_level); void ResetCredentialsInternal(SecurityLevel security_level);
void OnMediaDrmCreated(const ResetCredentialsCB& reset_credentials_cb,
scoped_refptr<media::MediaDrmBridge> media_drm_bridge);
// The MediaDrmBridge object used to perform the credential reset. // The MediaDrmBridge object used to perform the credential reset.
scoped_refptr<media::MediaDrmBridge> media_drm_bridge_; scoped_refptr<media::MediaDrmBridge> media_drm_bridge_;
......
...@@ -18,6 +18,24 @@ ...@@ -18,6 +18,24 @@
#include "url/gurl.h" #include "url/gurl.h"
namespace media { namespace media {
namespace {
void OnCdmCreated(const std::string& key_system,
MediaDrmBridge::SecurityLevel security_level,
const CdmCreatedCB& bound_cdm_created_cb,
scoped_refptr<MediaDrmBridge> cdm) {
if (!cdm) {
std::string error_message = "MediaDrmBridge cannot be created for " +
key_system + " with security level " +
base::IntToString(security_level);
LOG(ERROR) << error_message;
bound_cdm_created_cb.Run(nullptr, error_message);
return;
}
// Success!
bound_cdm_created_cb.Run(cdm, "");
}
} // namespace
AndroidCdmFactory::AndroidCdmFactory(const CreateFetcherCB& create_fetcher_cb, AndroidCdmFactory::AndroidCdmFactory(const CreateFetcherCB& create_fetcher_cb,
const CreateStorageCB& create_storage_cb) const CreateStorageCB& create_storage_cb)
...@@ -80,20 +98,12 @@ void AndroidCdmFactory::Create( ...@@ -80,20 +98,12 @@ void AndroidCdmFactory::Create(
return; return;
} }
scoped_refptr<MediaDrmBridge> cdm(MediaDrmBridge::Create( MediaDrmBridge::Create(key_system, security_origin, security_level,
key_system, security_origin, security_level, create_fetcher_cb_, create_fetcher_cb_, create_storage_cb_,
create_storage_cb_, session_message_cb, session_closed_cb, session_message_cb, session_closed_cb,
session_keys_change_cb, session_expiration_update_cb)); session_keys_change_cb, session_expiration_update_cb,
if (!cdm) { base::BindOnce(&OnCdmCreated, key_system,
error_message = "MediaDrmBridge cannot be created for " + key_system + security_level, bound_cdm_created_cb));
" with security level " + base::IntToString(security_level);
LOG(ERROR) << error_message;
bound_cdm_created_cb.Run(nullptr, error_message);
return;
}
// Success!
bound_cdm_created_cb.Run(cdm, "");
} }
} // namespace media } // namespace media
...@@ -319,36 +319,35 @@ std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() { ...@@ -319,36 +319,35 @@ std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() {
} }
// static // static
scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateInternal( void MediaDrmBridge::CreateInternal(
const std::string& key_system, const std::vector<uint8_t>& scheme_uuid,
const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
std::unique_ptr<MediaDrmStorageBridge> storage,
const CreateFetcherCB& create_fetcher_cb, const CreateFetcherCB& create_fetcher_cb,
const CreateStorageCB& create_storage_cb,
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb) { const SessionExpirationUpdateCB& session_expiration_update_cb,
CreatedCB created_cb) {
// All paths requires the MediaDrmApis. // All paths requires the MediaDrmApis.
DCHECK(AreMediaDrmApisAvailable()); DCHECK(AreMediaDrmApisAvailable());
DCHECK(!scheme_uuid.empty());
UUID scheme_uuid = GetKeySystemManager()->GetUUID(key_system);
if (scheme_uuid.empty())
return nullptr;
scoped_refptr<MediaDrmBridge> media_drm_bridge(new MediaDrmBridge( scoped_refptr<MediaDrmBridge> media_drm_bridge(new MediaDrmBridge(
scheme_uuid, security_origin, security_level, create_fetcher_cb, scheme_uuid, security_level, std::move(storage), create_fetcher_cb,
create_storage_cb, session_message_cb, session_closed_cb, session_message_cb, session_closed_cb, session_keys_change_cb,
session_keys_change_cb, session_expiration_update_cb)); session_expiration_update_cb));
if (media_drm_bridge->j_media_drm_.is_null()) if (media_drm_bridge->j_media_drm_.is_null())
media_drm_bridge = nullptr; media_drm_bridge = nullptr;
return media_drm_bridge; // Return |media_drm_bridge| asynchronously to make the callback binding
// easier.
std::move(created_cb).Run(std::move(media_drm_bridge));
} }
// static // static
scoped_refptr<MediaDrmBridge> MediaDrmBridge::Create( void MediaDrmBridge::Create(
const std::string& key_system, const std::string& key_system,
const GURL& security_origin, const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
...@@ -357,33 +356,59 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::Create( ...@@ -357,33 +356,59 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::Create(
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb) { const SessionExpirationUpdateCB& session_expiration_update_cb,
CreatedCB created_cb) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
if (!IsAvailable()) if (!IsAvailable()) {
return nullptr; std::move(created_cb).Run(nullptr);
return;
}
return CreateInternal(key_system, security_origin, security_level, UUID scheme_uuid = GetKeySystemManager()->GetUUID(key_system);
create_fetcher_cb, create_storage_cb, if (scheme_uuid.empty()) {
session_message_cb, session_closed_cb, std::move(created_cb).Run(nullptr);
session_keys_change_cb, session_expiration_update_cb); return;
}
// MediaDrmStorage may be lazy created in MediaDrmStorageBridge.
auto storage = base::MakeUnique<MediaDrmStorageBridge>();
MediaDrmStorageBridge* raw_storage = storage.get();
base::OnceClosure create_media_drm_cb = base::BindOnce(
&MediaDrmBridge::CreateInternal, scheme_uuid, security_level,
base::Passed(&storage), create_fetcher_cb, session_message_cb,
session_closed_cb, session_keys_change_cb, session_expiration_update_cb,
base::Passed(&created_cb));
if (IsPersistentLicenseTypeSupported(key_system) &&
!security_origin.is_empty() && !create_storage_cb.is_null()) {
raw_storage->Initialize(url::Origin(security_origin), create_storage_cb,
std::move(create_media_drm_cb));
} else {
std::move(create_media_drm_cb).Run();
}
} }
// static // static
scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport( void MediaDrmBridge::CreateWithoutSessionSupport(
const std::string& key_system, const std::string& key_system,
SecurityLevel security_level, SecurityLevel security_level,
const CreateFetcherCB& create_fetcher_cb) { const CreateFetcherCB& create_fetcher_cb,
CreatedCB created_cb) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
// Sessions won't be used so decoding capability is not required. // Sessions won't be used so decoding capability is not required.
if (!AreMediaDrmApisAvailable()) if (!AreMediaDrmApisAvailable()) {
return nullptr; std::move(created_cb).Run(nullptr);
return;
}
return MediaDrmBridge::Create( MediaDrmBridge::Create(key_system, GURL::EmptyGURL(), security_level,
key_system, GURL::EmptyGURL(), security_level, create_fetcher_cb, create_fetcher_cb, CreateStorageCB(),
CreateStorageCB(), SessionMessageCB(), SessionClosedCB(), SessionMessageCB(), SessionClosedCB(),
SessionKeysChangeCB(), SessionExpirationUpdateCB()); SessionKeysChangeCB(), SessionExpirationUpdateCB(),
std::move(created_cb));
} }
void MediaDrmBridge::SetServerCertificate( void MediaDrmBridge::SetServerCertificate(
...@@ -801,16 +826,15 @@ void MediaDrmBridge::OnResetDeviceCredentialsCompleted( ...@@ -801,16 +826,15 @@ void MediaDrmBridge::OnResetDeviceCredentialsCompleted(
MediaDrmBridge::MediaDrmBridge( MediaDrmBridge::MediaDrmBridge(
const std::vector<uint8_t>& scheme_uuid, const std::vector<uint8_t>& scheme_uuid,
const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
std::unique_ptr<MediaDrmStorageBridge> storage,
const CreateFetcherCB& create_fetcher_cb, const CreateFetcherCB& create_fetcher_cb,
const CreateStorageCB& create_storage_cb,
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb) const SessionExpirationUpdateCB& session_expiration_update_cb)
: scheme_uuid_(scheme_uuid), : scheme_uuid_(scheme_uuid),
storage_(url::Origin(security_origin), create_storage_cb), storage_(std::move(storage)),
create_fetcher_cb_(create_fetcher_cb), create_fetcher_cb_(create_fetcher_cb),
session_message_cb_(session_message_cb), session_message_cb_(session_message_cb),
session_closed_cb_(session_closed_cb), session_closed_cb_(session_closed_cb),
...@@ -821,7 +845,8 @@ MediaDrmBridge::MediaDrmBridge( ...@@ -821,7 +845,8 @@ MediaDrmBridge::MediaDrmBridge(
weak_factory_(this) { weak_factory_(this) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
DCHECK(!create_fetcher_cb_.is_null()); DCHECK(storage_);
DCHECK(create_fetcher_cb_);
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
CHECK(env); CHECK(env);
...@@ -838,13 +863,16 @@ MediaDrmBridge::MediaDrmBridge( ...@@ -838,13 +863,16 @@ MediaDrmBridge::MediaDrmBridge(
// supported and check if origin is valid. // supported and check if origin is valid.
base::FeatureList::IsEnabled(kMediaDrmPersistentLicense) && base::FeatureList::IsEnabled(kMediaDrmPersistentLicense) &&
// MediaDrm implements origin isolated storage on M. // MediaDrm implements origin isolated storage on M.
base::android::BuildInfo::GetInstance()->sdk_int() >= 23; base::android::BuildInfo::GetInstance()->sdk_int() >= 23 &&
// origin id can be empty when MediaDrmBridge is created by
// CreateWithoutSessionSupport, which is used to reset credentials.
!storage_->origin_id().empty();
// TODO(yucliu): Per EME spec on individualization, implementation should not // TODO(yucliu): Per EME spec on individualization, implementation should not
// expose application-specific information. Considering encode origin before // expose application-specific information. Considering encode origin before
// passing to MediaDrm. // passing to MediaDrm.
ScopedJavaLocalRef<jstring> j_security_origin = ConvertUTF8ToJavaString( ScopedJavaLocalRef<jstring> j_security_origin = ConvertUTF8ToJavaString(
env, use_origin_isolated_storage ? security_origin.spec() : ""); env, use_origin_isolated_storage ? storage_->origin_id() : "");
// TODO(yucliu): Use |create_storage_cb_| to create MediaDrmStorage which can // TODO(yucliu): Use |create_storage_cb_| to create MediaDrmStorage which can
// be used by Java side to store/retrieve persistent data. This should only // be used by Java side to store/retrieve persistent data. This should only
...@@ -853,7 +881,8 @@ MediaDrmBridge::MediaDrmBridge( ...@@ -853,7 +881,8 @@ MediaDrmBridge::MediaDrmBridge(
// Note: OnMediaCryptoReady() could be called in this call. // Note: OnMediaCryptoReady() could be called in this call.
j_media_drm_.Reset(Java_MediaDrmBridge_create( j_media_drm_.Reset(Java_MediaDrmBridge_create(
env, j_scheme_uuid, j_security_origin, j_security_level, env, j_scheme_uuid, j_security_origin, j_security_level,
reinterpret_cast<intptr_t>(this), reinterpret_cast<intptr_t>(&storage_))); reinterpret_cast<intptr_t>(this),
reinterpret_cast<intptr_t>(storage_.get())));
} }
MediaDrmBridge::~MediaDrmBridge() { MediaDrmBridge::~MediaDrmBridge() {
......
...@@ -68,6 +68,8 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule, ...@@ -68,6 +68,8 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
base::Callback<void(JavaObjectPtr media_crypto, base::Callback<void(JavaObjectPtr media_crypto,
bool requires_secure_video_codec)>; bool requires_secure_video_codec)>;
using CreatedCB = base::OnceCallback<void(scoped_refptr<MediaDrmBridge>)>;
// Checks whether MediaDRM is available and usable, including for decoding. // Checks whether MediaDRM is available and usable, including for decoding.
// All other static methods check IsAvailable() or equivalent internally. // All other static methods check IsAvailable() or equivalent internally.
// There is no need to check IsAvailable() explicitly before calling them. // There is no need to check IsAvailable() explicitly before calling them.
...@@ -93,7 +95,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule, ...@@ -93,7 +95,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
// Returns a MediaDrmBridge instance if |key_system| and |security_level| are // Returns a MediaDrmBridge instance if |key_system| and |security_level| are
// supported, and nullptr otherwise. The default security level will be used // supported, and nullptr otherwise. The default security level will be used
// if |security_level| is SECURITY_LEVEL_DEFAULT. // if |security_level| is SECURITY_LEVEL_DEFAULT.
static scoped_refptr<MediaDrmBridge> Create( static void Create(
const std::string& key_system, const std::string& key_system,
const GURL& security_origin, const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
...@@ -102,16 +104,18 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule, ...@@ -102,16 +104,18 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb); const SessionExpirationUpdateCB& session_expiration_update_cb,
CreatedCB created_cb);
// Same as Create() except that no session callbacks are provided. This is // Same as Create() except that no session callbacks are provided. This is
// used when we need to use MediaDrmBridge without creating any sessions. // used when we need to use MediaDrmBridge without creating any sessions.
// TODO(yucliu): Pass |security_origin| here to clear per-origin certs and // TODO(yucliu): Pass |security_origin| here to clear per-origin certs and
// licenses. // licenses.
static scoped_refptr<MediaDrmBridge> CreateWithoutSessionSupport( static void CreateWithoutSessionSupport(
const std::string& key_system, const std::string& key_system,
SecurityLevel security_level, SecurityLevel security_level,
const CreateFetcherCB& create_fetcher_cb); const CreateFetcherCB& create_fetcher_cb,
CreatedCB created_cb);
// ContentDecryptionModule implementation. // ContentDecryptionModule implementation.
void SetServerCertificate( void SetServerCertificate(
...@@ -246,26 +250,25 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule, ...@@ -246,26 +250,25 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
// For DeleteSoon() in DeleteOnCorrectThread(). // For DeleteSoon() in DeleteOnCorrectThread().
friend class base::DeleteHelper<MediaDrmBridge>; friend class base::DeleteHelper<MediaDrmBridge>;
static scoped_refptr<MediaDrmBridge> CreateInternal( static void CreateInternal(
const std::string& key_system, const std::vector<uint8_t>& scheme_uuid,
const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
std::unique_ptr<MediaDrmStorageBridge> storage,
const CreateFetcherCB& create_fetcher_cb, const CreateFetcherCB& create_fetcher_cb,
const CreateStorageCB& create_storage_cb,
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb); const SessionExpirationUpdateCB& session_expiration_update_cb,
CreatedCB bound_cdm_created_cb);
// Constructs a MediaDrmBridge for |scheme_uuid| and |security_level|. The // Constructs a MediaDrmBridge for |scheme_uuid| and |security_level|. The
// default security level will be used if |security_level| is // default security level will be used if |security_level| is
// SECURITY_LEVEL_DEFAULT. Sessions should not be created if session callbacks // SECURITY_LEVEL_DEFAULT. Sessions should not be created if session callbacks
// are null. // are null.
MediaDrmBridge(const std::vector<uint8_t>& scheme_uuid, MediaDrmBridge(const std::vector<uint8_t>& scheme_uuid,
const GURL& security_origin,
SecurityLevel security_level, SecurityLevel security_level,
std::unique_ptr<MediaDrmStorageBridge> storage,
const CreateFetcherCB& create_fetcher_cb, const CreateFetcherCB& create_fetcher_cb,
const CreateStorageCB& create_storage_cb,
const SessionMessageCB& session_message_cb, const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb, const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb, const SessionKeysChangeCB& session_keys_change_cb,
...@@ -293,7 +296,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule, ...@@ -293,7 +296,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
std::vector<uint8_t> scheme_uuid_; std::vector<uint8_t> scheme_uuid_;
// Persistent storage for session ID map. // Persistent storage for session ID map.
MediaDrmStorageBridge storage_; std::unique_ptr<MediaDrmStorageBridge> storage_;
// Java MediaDrm instance. // Java MediaDrm instance.
base::android::ScopedJavaGlobalRef<jobject> j_media_drm_; base::android::ScopedJavaGlobalRef<jobject> j_media_drm_;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "media/base/android/media_drm_bridge.h" #include "media/base/android/media_drm_bridge.h"
#include "media/base/provision_fetcher.h" #include "media/base/provision_fetcher.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -60,6 +61,15 @@ class MockProvisionFetcher : public ProvisionFetcher { ...@@ -60,6 +61,15 @@ class MockProvisionFetcher : public ProvisionFetcher {
const ResponseCB& response_cb) override {} const ResponseCB& response_cb) override {}
}; };
void CheckMediaDrmBridge(bool expect_success,
scoped_refptr<MediaDrmBridge> media_drm_bridge) {
if (expect_success) {
EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(media_drm_bridge);
} else {
EXPECT_FALSE(media_drm_bridge);
}
}
} // namespace (anonymous) } // namespace (anonymous)
TEST(MediaDrmBridgeTest, IsKeySystemSupported_Widevine) { TEST(MediaDrmBridgeTest, IsKeySystemSupported_Widevine) {
...@@ -98,15 +108,21 @@ TEST(MediaDrmBridgeTest, IsKeySystemSupported_InvalidKeySystem) { ...@@ -98,15 +108,21 @@ TEST(MediaDrmBridgeTest, IsKeySystemSupported_InvalidKeySystem) {
TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_Widevine) { TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_Widevine) {
base::MessageLoop message_loop_; base::MessageLoop message_loop_;
EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(MediaDrmBridge::CreateWithoutSessionSupport( MediaDrmBridge::CreateWithoutSessionSupport(
kWidevineKeySystem, kDefault, base::Bind(&MockProvisionFetcher::Create))); kWidevineKeySystem, kDefault, base::Bind(&MockProvisionFetcher::Create),
base::BindOnce(&CheckMediaDrmBridge, true));
base::RunLoop().RunUntilIdle();
} }
// Invalid key system is NOT supported regardless whether MediaDrm is available. // Invalid key system is NOT supported regardless whether MediaDrm is available.
TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_InvalidKeySystem) { TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_InvalidKeySystem) {
base::MessageLoop message_loop_; base::MessageLoop message_loop_;
EXPECT_FALSE(MediaDrmBridge::CreateWithoutSessionSupport( MediaDrmBridge::CreateWithoutSessionSupport(
kInvalidKeySystem, kDefault, base::Bind(&MockProvisionFetcher::Create))); kInvalidKeySystem, kDefault, base::Bind(&MockProvisionFetcher::Create),
base::BindOnce(&CheckMediaDrmBridge, false));
base::RunLoop().RunUntilIdle();
} }
TEST(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) { TEST(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) {
...@@ -114,11 +130,15 @@ TEST(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) { ...@@ -114,11 +130,15 @@ TEST(MediaDrmBridgeTest, CreateWithSecurityLevel_Widevine) {
// We test "L3" fully. But for "L1" we don't check the result as it depends on // We test "L3" fully. But for "L1" we don't check the result as it depends on
// whether the test device supports "L1". // whether the test device supports "L1".
EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(MediaDrmBridge::CreateWithoutSessionSupport( MediaDrmBridge::CreateWithoutSessionSupport(
kWidevineKeySystem, kL3, base::Bind(&MockProvisionFetcher::Create))); kWidevineKeySystem, kL3, base::Bind(&MockProvisionFetcher::Create),
base::BindOnce(&CheckMediaDrmBridge, true));
MediaDrmBridge::CreateWithoutSessionSupport( MediaDrmBridge::CreateWithoutSessionSupport(
kWidevineKeySystem, kL1, base::Bind(&MockProvisionFetcher::Create)); kWidevineKeySystem, kL1, base::Bind(&MockProvisionFetcher::Create),
base::BindOnce([](scoped_refptr<MediaDrmBridge>) {}));
base::RunLoop().RunUntilIdle();
} }
} // namespace media } // namespace media
...@@ -33,25 +33,35 @@ bool MediaDrmStorageBridge::RegisterMediaDrmStorageBridge(JNIEnv* env) { ...@@ -33,25 +33,35 @@ bool MediaDrmStorageBridge::RegisterMediaDrmStorageBridge(JNIEnv* env) {
return RegisterNativesImpl(env); return RegisterNativesImpl(env);
} }
MediaDrmStorageBridge::MediaDrmStorageBridge( MediaDrmStorageBridge::MediaDrmStorageBridge()
const url::Origin& origin, : task_runner_(base::ThreadTaskRunnerHandle::Get()), weak_factory_(this) {}
const CreateStorageCB& create_storage_cb)
: create_storage_cb_(create_storage_cb),
origin_(origin),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_factory_(this) {}
MediaDrmStorageBridge::~MediaDrmStorageBridge() = default; MediaDrmStorageBridge::~MediaDrmStorageBridge() = default;
void MediaDrmStorageBridge::Initialize(const url::Origin& origin,
const CreateStorageCB& create_storage_cb,
base::OnceClosure on_init) {
DCHECK(create_storage_cb);
impl_ = create_storage_cb.Run();
// TODO(yucliu): MediaDrmStorage should generate and return origin id
// asynchronously in a callback.
impl_->Initialize(origin);
origin_id_ = origin.Serialize();
std::move(on_init).Run();
}
void MediaDrmStorageBridge::OnProvisioned( void MediaDrmStorageBridge::OnProvisioned(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& j_storage, const JavaParamRef<jobject>& j_storage,
// Callback<Boolean> // Callback<Boolean>
const JavaParamRef<jobject>& j_callback) { const JavaParamRef<jobject>& j_callback) {
DCHECK(impl_);
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&MediaDrmStorage::OnProvisioned, GetStorageImpl()->AsWeakPtr(), &MediaDrmStorage::OnProvisioned, impl_->AsWeakPtr(),
base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback, base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback,
// Bind callback to WeakPtr in case callback is called // Bind callback to WeakPtr in case callback is called
// after object is deleted. // after object is deleted.
...@@ -65,12 +75,13 @@ void MediaDrmStorageBridge::OnLoadInfo( ...@@ -65,12 +75,13 @@ void MediaDrmStorageBridge::OnLoadInfo(
const JavaParamRef<jbyteArray>& j_session_id, const JavaParamRef<jbyteArray>& j_session_id,
// Callback<PersistentInfo> // Callback<PersistentInfo>
const JavaParamRef<jobject>& j_callback) { const JavaParamRef<jobject>& j_callback) {
DCHECK(impl_);
std::string session_id = JavaBytesToString(env, j_session_id); std::string session_id = JavaBytesToString(env, j_session_id);
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&MediaDrmStorage::LoadPersistentSession, &MediaDrmStorage::LoadPersistentSession, impl_->AsWeakPtr(),
GetStorageImpl()->AsWeakPtr(), session_id, session_id,
base::BindOnce(&MediaDrmStorageBridge::OnSessionDataLoaded, base::BindOnce(&MediaDrmStorageBridge::OnSessionDataLoaded,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
base::Passed(CreateJavaObjectPtr(j_callback.obj())), base::Passed(CreateJavaObjectPtr(j_callback.obj())),
...@@ -83,6 +94,7 @@ void MediaDrmStorageBridge::OnSaveInfo( ...@@ -83,6 +94,7 @@ void MediaDrmStorageBridge::OnSaveInfo(
const JavaParamRef<jobject>& j_persist_info, const JavaParamRef<jobject>& j_persist_info,
// Callback<Boolean> // Callback<Boolean>
const JavaParamRef<jobject>& j_callback) { const JavaParamRef<jobject>& j_callback) {
DCHECK(impl_);
std::vector<uint8_t> key_set_id; std::vector<uint8_t> key_set_id;
JavaByteArrayToByteVector( JavaByteArrayToByteVector(
env, Java_PersistentInfo_keySetId(env, j_persist_info.obj()).obj(), env, Java_PersistentInfo_keySetId(env, j_persist_info.obj()).obj(),
...@@ -97,8 +109,8 @@ void MediaDrmStorageBridge::OnSaveInfo( ...@@ -97,8 +109,8 @@ void MediaDrmStorageBridge::OnSaveInfo(
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&MediaDrmStorage::SavePersistentSession, &MediaDrmStorage::SavePersistentSession, impl_->AsWeakPtr(),
GetStorageImpl()->AsWeakPtr(), session_id, session_id,
MediaDrmStorage::SessionData(std::move(key_set_id), std::move(mime)), MediaDrmStorage::SessionData(std::move(key_set_id), std::move(mime)),
base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback, base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
...@@ -111,11 +123,12 @@ void MediaDrmStorageBridge::OnClearInfo( ...@@ -111,11 +123,12 @@ void MediaDrmStorageBridge::OnClearInfo(
const JavaParamRef<jbyteArray>& j_session_id, const JavaParamRef<jbyteArray>& j_session_id,
// Callback<Boolean> // Callback<Boolean>
const JavaParamRef<jobject>& j_callback) { const JavaParamRef<jobject>& j_callback) {
DCHECK(impl_);
task_runner_->PostTask( task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
&MediaDrmStorage::RemovePersistentSession, &MediaDrmStorage::RemovePersistentSession, impl_->AsWeakPtr(),
GetStorageImpl()->AsWeakPtr(), JavaBytesToString(env, j_session_id), JavaBytesToString(env, j_session_id),
base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback, base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback,
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
base::Passed(CreateJavaObjectPtr(j_callback.obj()))))); base::Passed(CreateJavaObjectPtr(j_callback.obj())))));
...@@ -146,14 +159,4 @@ void MediaDrmStorageBridge::OnSessionDataLoaded( ...@@ -146,14 +159,4 @@ void MediaDrmStorageBridge::OnSessionDataLoaded(
env, j_eme_id, j_key_set_id, j_mime)); env, j_eme_id, j_key_set_id, j_mime));
} }
MediaDrmStorage* MediaDrmStorageBridge::GetStorageImpl() {
if (!impl_) {
DCHECK(create_storage_cb_);
impl_ = std::move(create_storage_cb_).Run();
impl_->Initialize(origin_);
}
return impl_.get();
}
} // namespace media } // namespace media
...@@ -29,10 +29,18 @@ class MediaDrmStorageBridge { ...@@ -29,10 +29,18 @@ class MediaDrmStorageBridge {
public: public:
static bool RegisterMediaDrmStorageBridge(JNIEnv* env); static bool RegisterMediaDrmStorageBridge(JNIEnv* env);
MediaDrmStorageBridge(const url::Origin& origin, MediaDrmStorageBridge();
const CreateStorageCB& create_storage_cb);
~MediaDrmStorageBridge(); ~MediaDrmStorageBridge();
// Bind origin to |this|. Once storage is initialized, |on_init| will be
// called and it will have a random generated origin id for later usage. If
// this function isn't called, all the other functions will fail.
void Initialize(const url::Origin& origin,
const CreateStorageCB& create_storage_cb,
base::OnceClosure init_cb);
std::string origin_id() const { return origin_id_; }
// The following OnXXX functions are called by Java. The functions will post // The following OnXXX functions are called by Java. The functions will post
// task on message loop immediately to avoid reentrancy issues. // task on message loop immediately to avoid reentrancy issues.
...@@ -73,12 +81,10 @@ class MediaDrmStorageBridge { ...@@ -73,12 +81,10 @@ class MediaDrmStorageBridge {
const std::string& session_id, const std::string& session_id,
std::unique_ptr<MediaDrmStorage::SessionData> session_data); std::unique_ptr<MediaDrmStorage::SessionData> session_data);
MediaDrmStorage* GetStorageImpl();
CreateStorageCB create_storage_cb_;
std::unique_ptr<MediaDrmStorage> impl_; std::unique_ptr<MediaDrmStorage> impl_;
const url::Origin origin_; // Randomly generated ID for origin.
std::string origin_id_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment