Source release v3.0.1 + third_party
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
# Make sure that a valid config.h for your target is in the source tree.
|
||||
'protobuf_config%': 'source',
|
||||
'protobuf_source%': '../third_party/protobuf',
|
||||
'protoc_host_target%': 'dummy',
|
||||
}, # variables
|
||||
'conditions': [
|
||||
['protobuf_config=="source"', {
|
||||
@@ -187,5 +188,9 @@
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
'target_name': 'dummy',
|
||||
'type': 'none',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
'test/test_host.cpp',
|
||||
'test/test_host.h',
|
||||
],
|
||||
'variables': {
|
||||
'cdm_dir': '..',
|
||||
},
|
||||
'includes': [
|
||||
'oemcrypto_unittests.gypi',
|
||||
'core_unittests.gypi',
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
'CORE_TESTS',
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm.gyp:license_protocol',
|
||||
# This gypi may be included from outside this folder, and dependencies in
|
||||
# a gypi are relative to the gyp file doing the including.
|
||||
# cdm_dir is a variable the including file must set to help us find the
|
||||
# correct path.
|
||||
'<(cdm_dir)/cdm/cdm.gyp:license_protocol',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -34,7 +34,17 @@ typedef __int64 int64_t;
|
||||
|
||||
namespace widevine {
|
||||
|
||||
class CDM_EXPORT Cdm {
|
||||
class CDM_EXPORT ITimerClient {
|
||||
public:
|
||||
// Called by ITimer when a timer expires.
|
||||
virtual void onTimerExpired(void* context) = 0;
|
||||
|
||||
protected:
|
||||
ITimerClient() {}
|
||||
virtual ~ITimerClient() {}
|
||||
};
|
||||
|
||||
class CDM_EXPORT Cdm : public ITimerClient {
|
||||
public:
|
||||
// Session types defined by EME.
|
||||
typedef enum {
|
||||
@@ -179,21 +189,17 @@ class CDM_EXPORT Cdm {
|
||||
// See Cdm::initialize().
|
||||
class ITimer {
|
||||
public:
|
||||
class IClient {
|
||||
public:
|
||||
// Called by ITimer when a timer expires.
|
||||
virtual void onTimerExpired(void* context) = 0;
|
||||
|
||||
protected:
|
||||
IClient() {}
|
||||
virtual ~IClient() {}
|
||||
};
|
||||
// This typedef is for backward compatibility with v3.0.0.
|
||||
typedef ITimerClient IClient;
|
||||
|
||||
// Call |client->onTimerExpired(context)| after a delay of |delay_ms| ms.
|
||||
virtual void setTimeout(int64_t delay_ms,
|
||||
IClient* client,
|
||||
void* context) = 0;
|
||||
|
||||
// Cancel all timers associated with |client|.
|
||||
virtual void cancel(IClient *client) = 0;
|
||||
|
||||
protected:
|
||||
ITimer() {}
|
||||
virtual ~ITimer() {}
|
||||
@@ -425,6 +431,27 @@ class CDM_EXPORT Cdm {
|
||||
virtual Status decrypt(const InputBuffer& input,
|
||||
const OutputBuffer& output) = 0;
|
||||
|
||||
// Sets a value in the custom app settings. These are settings
|
||||
// that are sent with any message to the license server. These methods
|
||||
// should only be used by advanced users maintaining existing systems.
|
||||
// The |key| cannot be empty.
|
||||
virtual Status setAppParameter(const std::string& key,
|
||||
const std::string& value) = 0;
|
||||
|
||||
// Gets the current value in the custom app settings. If the key is
|
||||
// not present, then kInvalidAccess is returned. The |key| cannot be
|
||||
// empty. |result| cannot be null. See setAppParameter().
|
||||
virtual Status getAppParameter(const std::string& key,
|
||||
std::string* result) = 0;
|
||||
|
||||
// Removes the value in the custom app settings. If the key is not
|
||||
// present, then kInvalidAccess is returned. The |key| cannot be empty.
|
||||
// See setAppParameter().
|
||||
virtual Status removeAppParameter(const std::string& key) = 0;
|
||||
|
||||
// Clears all the values in the custom app settings. See setAppParameter().
|
||||
virtual Status clearAppParameters() = 0;
|
||||
|
||||
protected:
|
||||
Cdm() {}
|
||||
};
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Widevine CE CDM Version
|
||||
#define CDM_VERSION "v3.0.0-0-g8d3792b-ce"
|
||||
#define CDM_VERSION "v3.0.1-0-g41710d9-ce"
|
||||
|
||||
@@ -105,7 +105,6 @@ class PropertySet : public CdmClientPropertySet {
|
||||
};
|
||||
|
||||
class CdmImpl : public Cdm,
|
||||
public Cdm::ITimer::IClient,
|
||||
public WvCdmEventListener {
|
||||
public:
|
||||
CdmImpl(IEventListener* listener,
|
||||
@@ -134,6 +133,16 @@ class CdmImpl : public Cdm,
|
||||
virtual Status getKeyStatuses(const std::string& session_id,
|
||||
KeyStatusMap* key_statuses) OVERRIDE;
|
||||
|
||||
virtual Status setAppParameter(const std::string& key,
|
||||
const std::string& value) OVERRIDE;
|
||||
|
||||
virtual Status getAppParameter(const std::string& key,
|
||||
std::string* result) OVERRIDE;
|
||||
|
||||
virtual Status removeAppParameter(const std::string& key) OVERRIDE;
|
||||
|
||||
virtual Status clearAppParameters() OVERRIDE;
|
||||
|
||||
virtual Status close(const std::string& session_id) OVERRIDE;
|
||||
|
||||
virtual Status remove(const std::string& session_id) OVERRIDE;
|
||||
@@ -141,7 +150,7 @@ class CdmImpl : public Cdm,
|
||||
virtual Status decrypt(const InputBuffer& input,
|
||||
const OutputBuffer& output) OVERRIDE;
|
||||
|
||||
// ITimer::IClient:
|
||||
// ITimerClient:
|
||||
virtual void onTimerExpired(void* context) OVERRIDE;
|
||||
|
||||
// WvCdmEventListener:
|
||||
@@ -160,6 +169,7 @@ class CdmImpl : public Cdm,
|
||||
|
||||
CdmEngine cdm_engine_;
|
||||
PropertySet property_set_;
|
||||
CdmAppParameterMap app_parameters_;
|
||||
|
||||
std::map<std::string, SessionType> new_session_types_;
|
||||
std::map<std::string, int64_t> session_expirations_;
|
||||
@@ -173,7 +183,9 @@ CdmImpl::CdmImpl(IEventListener* listener,
|
||||
property_set_.set_use_privacy_mode(privacy_mode);
|
||||
}
|
||||
|
||||
CdmImpl::~CdmImpl() {}
|
||||
CdmImpl::~CdmImpl() {
|
||||
host.timer->cancel(this);
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::setServerCertificate(const std::string& certificate) {
|
||||
if (!property_set_.use_privacy_mode()) {
|
||||
@@ -283,14 +295,13 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
||||
return kInvalidAccess;
|
||||
}
|
||||
|
||||
CdmAppParameterMap empty_app_parameters;
|
||||
std::string key_request;
|
||||
CdmKeyRequestType key_request_type;
|
||||
std::string ignored_server_url;
|
||||
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, init_data_obj,
|
||||
license_type, empty_app_parameters, &key_request, &key_request_type,
|
||||
license_type, app_parameters_, &key_request, &key_request_type,
|
||||
&ignored_server_url, NULL);
|
||||
|
||||
if (result != KEY_MESSAGE) {
|
||||
@@ -349,13 +360,12 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
|
||||
// This was partially removed already.
|
||||
// The EME spec states that we should send a release message right away.
|
||||
InitializationData empty_initialization_data;
|
||||
CdmAppParameterMap empty_app_parameters;
|
||||
CdmKeyMessage key_request;
|
||||
std::string ignored_server_url;
|
||||
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, empty_initialization_data,
|
||||
kLicenseTypeRelease, empty_app_parameters, &key_request, NULL,
|
||||
kLicenseTypeRelease, app_parameters_, &key_request, NULL,
|
||||
&ignored_server_url, NULL);
|
||||
if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
@@ -412,14 +422,13 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
|
||||
// The underlying session in CdmEngine has stored a copy of the original
|
||||
// init data, so we can use an empty one this time.
|
||||
InitializationData empty_init_data;
|
||||
CdmAppParameterMap empty_app_parameters;
|
||||
std::string key_request;
|
||||
CdmKeyRequestType key_request_type;
|
||||
std::string ignored_server_url;
|
||||
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, empty_init_data, kLicenseTypeDeferred,
|
||||
empty_app_parameters, &key_request, &key_request_type,
|
||||
app_parameters_, &key_request, &key_request_type,
|
||||
&ignored_server_url, NULL);
|
||||
|
||||
if (result != KEY_MESSAGE) {
|
||||
@@ -476,6 +485,42 @@ Cdm::Status CdmImpl::getKeyStatuses(const std::string& session_id,
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::setAppParameter(const std::string& key,
|
||||
const std::string& value) {
|
||||
if (key.empty()) {
|
||||
return kInvalidAccess;
|
||||
}
|
||||
app_parameters_[key] = value;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::getAppParameter(const std::string& key,
|
||||
std::string* result) {
|
||||
if (NULL == result || key.empty() ||
|
||||
app_parameters_.find(key) == app_parameters_.end()) {
|
||||
return kInvalidAccess;
|
||||
}
|
||||
*result = app_parameters_[key];
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::removeAppParameter(const std::string& key) {
|
||||
if (key.empty()) {
|
||||
return kInvalidAccess;
|
||||
}
|
||||
CdmAppParameterMap::iterator it = app_parameters_.find(key);
|
||||
if (it == app_parameters_.end()) {
|
||||
return kInvalidAccess;
|
||||
}
|
||||
app_parameters_.erase(it);
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::clearAppParameters() {
|
||||
app_parameters_.clear();
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::close(const std::string& session_id) {
|
||||
if (!cdm_engine_.IsOpenSession(session_id)) {
|
||||
LOGE("No such session: %s", session_id.c_str());
|
||||
@@ -507,13 +552,12 @@ Cdm::Status CdmImpl::remove(const std::string& session_id) {
|
||||
}
|
||||
|
||||
InitializationData empty_initialization_data;
|
||||
CdmAppParameterMap empty_app_parameters;
|
||||
CdmKeyMessage key_request;
|
||||
std::string ignored_server_url;
|
||||
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, empty_initialization_data,
|
||||
kLicenseTypeRelease, empty_app_parameters, &key_request, NULL,
|
||||
kLicenseTypeRelease, app_parameters_, &key_request, NULL,
|
||||
&ignored_server_url, NULL);
|
||||
if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "cdm_test_printers.h"
|
||||
#include "license_request.h"
|
||||
#include "log.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "override.h"
|
||||
#include "properties_ce.h"
|
||||
#include "scoped_ptr.h"
|
||||
@@ -103,6 +104,12 @@ const std::vector<uint8_t> kOutput1 = a2b_hex(
|
||||
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
||||
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659");
|
||||
|
||||
const std::string kValue = "A Value";
|
||||
const std::string kNewValue = "A New Value";
|
||||
|
||||
const std::string kParamName = "PARAM";
|
||||
const std::string kParamName2 = "PARAM2";
|
||||
|
||||
|
||||
class CdmTest : public Test,
|
||||
public Cdm::IEventListener {
|
||||
@@ -423,6 +430,20 @@ TEST_F(CdmTest, Initialize) {
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, DeviceCertificateRequest) {
|
||||
uint32_t nonce = 0;
|
||||
uint8_t buffer[1];
|
||||
size_t size = 0;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
|
||||
int result = OEMCrypto_RewrapDeviceRSAKey(
|
||||
0, buffer, 0, buffer, 0, &nonce, buffer, 0, buffer, buffer, &size);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate());
|
||||
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
LOGW("WARNING: Skipping DeviceCertificateRequest because the device does "
|
||||
"not support provisioning. If you are using a baked-in certificate, "
|
||||
"this is expected. Otherwise, something is wrong.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear any existing certificates.
|
||||
g_host->remove("cert.bin");
|
||||
|
||||
@@ -1075,4 +1096,84 @@ TEST_F(CdmTest, ServerCertificateProvisioning) {
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, SetAppParameters) {
|
||||
// Must use privacy_mode = false to ensure that the message is in plain-text.
|
||||
std::string session_id;
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
|
||||
Cdm::Status status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Set a new app parameter, and check by getting.
|
||||
std::string result;
|
||||
status = cdm_->setAppParameter(kParamName, kValue);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->getAppParameter(kParamName, &result);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
ASSERT_EQ(kValue, result);
|
||||
|
||||
// Try to get using a null result.
|
||||
status = cdm_->getAppParameter(kParamName, NULL);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Try to get using an empty key.
|
||||
status = cdm_->getAppParameter("", &result);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Try to set using an empty key.
|
||||
status = cdm_->setAppParameter("", kValue);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Try to remove using an empty key.
|
||||
status = cdm_->removeAppParameter("");
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Change an existing app parameter.
|
||||
status = cdm_->setAppParameter(kParamName, kNewValue);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->getAppParameter(kParamName, &result);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
ASSERT_EQ(kNewValue, result);
|
||||
|
||||
// Remove an existing app parameter, check for invalid access when it's gone.
|
||||
status = cdm_->removeAppParameter(kParamName);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->getAppParameter(kParamName, &result);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Try to remove an absent value.
|
||||
status = cdm_->removeAppParameter(kParamName2);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
|
||||
// Set some values to check for.
|
||||
status = cdm_->setAppParameter(kParamName, kValue);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->setAppParameter(kParamName2, kNewValue);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Send a generate request to ensure the parameter is in the message.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_TRUE(!message.empty() && message.find(kValue) != std::string::npos);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Ensure that the value is still present and correct.
|
||||
status = cdm_->getAppParameter(kParamName, &result);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
ASSERT_EQ(kValue, result);
|
||||
status = cdm_->getAppParameter(kParamName2, &result);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
ASSERT_EQ(kNewValue, result);
|
||||
|
||||
// Clear all the parameters.
|
||||
status = cdm_->clearAppParameters();
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->getAppParameter(kParamName, &result);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
status = cdm_->getAppParameter(kParamName2, &result);
|
||||
ASSERT_EQ(Cdm::kInvalidAccess, status);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -91,3 +91,20 @@ void TestHost::setTimeout(int64_t delay_ms,
|
||||
int64_t expiry_time = now_ + delay_ms;
|
||||
timers_.push(Timer(expiry_time, client, context));
|
||||
}
|
||||
|
||||
void TestHost::cancel(IClient* client) {
|
||||
// Filter out the timers for this client and put the rest into |others|.
|
||||
std::priority_queue<Timer> others;
|
||||
|
||||
while (timers_.size()) {
|
||||
Timer t = timers_.top();
|
||||
timers_.pop();
|
||||
|
||||
if (t.client != client) {
|
||||
others.push(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Now swap the queues.
|
||||
timers_.swap(others);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class TestHost : public widevine::Cdm::IStorage,
|
||||
virtual void setTimeout(int64_t delay_ms,
|
||||
IClient* client,
|
||||
void* context) OVERRIDE;
|
||||
virtual void cancel(IClient* client) OVERRIDE;
|
||||
|
||||
private:
|
||||
struct Timer {
|
||||
|
||||
Reference in New Issue
Block a user