Builds libwvmdrmengine.so, which is loaded by the new MediaDrm APIs to support playback of Widevine/CENC protected content. Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
250 lines
8.5 KiB
C++
250 lines
8.5 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
|
|
#include "config_test_env.h"
|
|
#include "gtest/gtest.h"
|
|
#include "license_request.h"
|
|
#include "log.h"
|
|
#include "string_conversions.h"
|
|
#include "url_request.h"
|
|
#include "wv_content_decryption_module.h"
|
|
|
|
namespace {
|
|
// Default license server, can be configured using --server command line option
|
|
// Default key id (pssh), can be configured using --keyid command line option
|
|
std::string g_client_auth;
|
|
wvcdm::KeyId g_key_id;
|
|
wvcdm::CdmKeySystem g_key_system;
|
|
std::string g_license_server;
|
|
std::string g_port;
|
|
wvcdm::KeyId g_wrong_key_id;
|
|
int g_use_full_path = 0; // cannot use boolean in getopt_long
|
|
} // namespace
|
|
|
|
namespace wvcdm {
|
|
|
|
class WvCdmRequestLicenseTest : public testing::Test {
|
|
public:
|
|
WvCdmRequestLicenseTest() {}
|
|
~WvCdmRequestLicenseTest() {}
|
|
|
|
protected:
|
|
void GenerateKeyRequest(const std::string& key_system,
|
|
const std::string& init_data) {
|
|
wvcdm::CdmNameValueMap app_parameters;
|
|
EXPECT_EQ(decryptor_.GenerateKeyRequest(session_id_,
|
|
init_data,
|
|
kLicenseTypeStreaming,
|
|
app_parameters,
|
|
&key_msg_), wvcdm::KEY_MESSAGE);
|
|
}
|
|
|
|
void GenerateRenewalRequest(const std::string& key_system,
|
|
const std::string& init_data) {
|
|
// TODO application makes a license request, CDM will renew the license
|
|
// when appropriate.
|
|
wvcdm::CdmNameValueMap app_parameters;
|
|
EXPECT_EQ(decryptor_.GenerateKeyRequest(session_id_,
|
|
init_data,
|
|
kLicenseTypeStreaming,
|
|
app_parameters,
|
|
&key_msg_), wvcdm::KEY_MESSAGE);
|
|
}
|
|
|
|
// posts a request and extracts the drm message from the response
|
|
std::string GetKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth,
|
|
int expected_response) {
|
|
UrlRequest url_request(server_url + client_auth, g_port);
|
|
|
|
if (!url_request.is_connected()) {
|
|
return "";
|
|
}
|
|
|
|
url_request.PostRequest(key_msg_);
|
|
std::string response;
|
|
int resp_bytes = url_request.GetResponse(response);
|
|
LOGD("response:\r\n%s", response.c_str());
|
|
LOGD("end %d bytes response dump", resp_bytes);
|
|
|
|
// Youtube server returns 400 for invalid message while play server returns
|
|
// 500, so just test inequity here for invalid message
|
|
int status_code = url_request.GetStatusCode(response);
|
|
if (expected_response == 200) {
|
|
EXPECT_EQ(200, status_code);
|
|
} else {
|
|
EXPECT_NE(200, status_code);
|
|
}
|
|
|
|
std::string drm_msg;
|
|
if (200 == status_code) {
|
|
LicenseRequest lic_request;
|
|
lic_request.GetDrmMessage(response, drm_msg);
|
|
LOGV("drm msg: %u bytes\r\n%s", drm_msg.size(),
|
|
HexEncode(reinterpret_cast<const uint8_t*>(drm_msg.data()),
|
|
drm_msg.size()).c_str());
|
|
}
|
|
return drm_msg;
|
|
}
|
|
|
|
void VerifyKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth,
|
|
std::string& init_data,
|
|
bool is_renewal) {
|
|
std::string resp = GetKeyRequestResponse(server_url,
|
|
client_auth,
|
|
200);
|
|
|
|
if (is_renewal) {
|
|
// TODO application makes a license request, CDM will renew the license
|
|
// when appropriate
|
|
wvcdm::CdmNameValueMap app_parameters;
|
|
EXPECT_EQ(decryptor_.GenerateKeyRequest(session_id_,
|
|
init_data,
|
|
kLicenseTypeStreaming,
|
|
app_parameters,
|
|
&key_msg_), wvcdm::KEY_ADDED);
|
|
}
|
|
else {
|
|
EXPECT_EQ(decryptor_.AddKey(session_id_, resp), wvcdm::KEY_ADDED);
|
|
}
|
|
}
|
|
|
|
wvcdm::WvContentDecryptionModule decryptor_;
|
|
std::string key_msg_;
|
|
std::string session_id_;
|
|
};
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
GenerateKeyRequest(g_key_system, g_key_id);
|
|
GetKeyRequestResponse(g_license_server, g_client_auth, 200);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, WrongMessageTest) {
|
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
|
|
std::string wrong_message = wvcdm::a2bs_hex(g_wrong_key_id);
|
|
GenerateKeyRequest(g_key_system, wrong_message);
|
|
GetKeyRequestResponse(g_license_server, g_client_auth, 500);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, NormalDecryption) {
|
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
GenerateKeyRequest(g_key_system, g_key_id);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
#if 0
|
|
// TODO License renewal is not yet implented
|
|
TEST_F(WvCdmRequestLicenseTest, LicenseRenewal) {
|
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
GenerateKeyRequest(g_key_system, g_key_id);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
|
|
|
GenerateRenewalRequest(g_key_system, g_key_id);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, true);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
#endif
|
|
|
|
} // namespace wvcdm
|
|
|
|
int main(int argc, char **argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
wvcdm::ConfigTestEnv config;
|
|
g_client_auth.assign(config.client_auth());
|
|
g_key_system.assign(config.key_system());
|
|
g_wrong_key_id.assign(config.wrong_key_id());
|
|
|
|
// The following variables are configurable through command line options.
|
|
g_license_server.assign(config.license_server());
|
|
g_key_id.assign(config.key_id());
|
|
g_port.assign(config.port());
|
|
std::string license_server(g_license_server);
|
|
|
|
int show_usage = 0;
|
|
static const struct option long_options[] = {
|
|
{ "use_full_path", no_argument, &g_use_full_path, 0 },
|
|
{ "keyid", required_argument, NULL, 'k' },
|
|
{ "port", required_argument, NULL, 'p' },
|
|
{ "server", required_argument, NULL, 's' },
|
|
{ NULL, 0, NULL, '\0' }
|
|
};
|
|
|
|
int option_index = 0;
|
|
int opt = 0;
|
|
while ((opt = getopt_long(argc, argv, "k:p:s:u", long_options, &option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'k': {
|
|
g_key_id.clear();
|
|
g_key_id.assign(optarg);
|
|
break;
|
|
}
|
|
case 'p': {
|
|
g_port.clear();
|
|
g_port.assign(optarg);
|
|
break;
|
|
}
|
|
case 's': {
|
|
g_license_server.clear();
|
|
g_license_server.assign(optarg);
|
|
break;
|
|
}
|
|
case 'u': {
|
|
g_use_full_path = 1;
|
|
break;
|
|
}
|
|
case '?': {
|
|
show_usage = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (show_usage) {
|
|
std::cout << std::endl;
|
|
std::cout << "usage: " << argv[0] << " [options]" << std::endl << std::endl;
|
|
std::cout << " enclose multiple arguments in '' when using adb shell" << std::endl;
|
|
std::cout << " e.g. adb shell '" << argv[0] << " --server=\"url\"'" << std::endl << std::endl;
|
|
|
|
std::cout << std::setw(30) << std::left << " --port=<connection port>";
|
|
std::cout << "specifies the port number, in decimal format" << std::endl;
|
|
std::cout << std::setw(30) << std::left << " ";
|
|
std::cout << "default: " << g_port << std::endl;
|
|
|
|
std::cout << std::setw(30) << std::left << " --server=<server_url>";
|
|
std::cout << "configure the license server url, please include http[s] in the url" << std::endl;
|
|
std::cout << std::setw(30) << std::left << " ";
|
|
std::cout << "default: " << license_server << std::endl;
|
|
|
|
std::cout << std::setw(30) << std::left << " --keyid=<key_id>";
|
|
std::cout << "configure the key id or pssh, in hex format" << std::endl;
|
|
std::cout << std::setw(30) << std::left << " default keyid:";
|
|
std::cout << g_key_id << std::endl;
|
|
|
|
std::cout << std::setw(30) << std::left << " --use_full_path";
|
|
std::cout << "specify server url is not a proxy server" << std::endl;
|
|
std::cout << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
std::cout << "Server: " << g_license_server << std::endl;
|
|
std::cout << "Port: " << g_port << std::endl;
|
|
std::cout << "KeyID: " << g_key_id << std::endl << std::endl;
|
|
|
|
g_key_id = wvcdm::a2bs_hex(g_key_id);
|
|
config.set_license_server(g_license_server);
|
|
config.set_port(g_port);
|
|
config.set_key_id(g_key_id);
|
|
|
|
return RUN_ALL_TESTS();
|
|
}
|