Merge Changes from CDM repository

This CL merges the following changes from the Widevine repository:

Avoid CdmSession reinitialization
https://widevine-internal-review.googlesource.com/#/c/10530/

Fix timer-related unit tests.
https://widevine-internal-review.googlesource.com/#/c/10510/

Correct return statement
bug: 15590802
https://widevine-internal-review.googlesource.com/#/c/10553/

Usage reporting fixes
bug/15388863
https://widevine-internal-review.googlesource.com/#/c/10460/

Make public methods virtual
https://widevine-internal-review.googlesource.com/#/c/10500/

Fix the SetTimer contract in the CDM.
https://widevine-internal-review.googlesource.com/#/c/10493/

Move inline CDM methods, add OVERRIDE.
https://widevine-internal-review.googlesource.com/#/c/10475/

Simplify storage APIs related cleanup.
https://widevine-internal-review.googlesource.com/#/c/10473/

Duration values are not correctly reported when queried
b/15592374
https://widevine-internal-review.googlesource.com/#/c/10437/

Propagate IsKeyValid() through ContentDecryptionModule.
https://widevine-internal-review.googlesource.com/#/c/10483/

Minor clean up in config_test_env.
https://widevine-internal-review.googlesource.com/#/c/10440/

General clean up.
https://widevine-internal-review.googlesource.com/#/c/10441/

Refactor HttpSocket and simplify UrlRequest interface.
https://widevine-internal-review.googlesource.com/#/c/10410/

Install good keybox at end of unit tests
b/15385981
https://widevine-internal-review.googlesource.com/#/c/10374/

Privacy crypto fixes
b/15475012
https://widevine-internal-review.googlesource.com/#/c/10383/

Incorporate header files to resolve build issued based on customers feedback.
https://widevine-internal-review.googlesource.com/#/c/10420/

Support unprovisioning
b/12247651
https://widevine-internal-review.googlesource.com/#/c/10356/

Correct usage of Host::Allocate and Cdm::Decrypt.
https://widevine-internal-review.googlesource.com/#/c/10378/

Fix logging bug, arguments in wrong order.
https://widevine-internal-review.googlesource.com/#/c/10380/

Rename types that look like constants.
https://widevine-internal-review.googlesource.com/#/c/10379/

Fix offline test failures
b/13909635
https://widevine-internal-review.googlesource.com/#/c/10348/

Add -DUNIT_TEST to the unit test makefile for Android
https://widevine-internal-review.googlesource.com/#/c/10375/

Refactor privacy-crypto and add dummy version.
https://widevine-internal-review.googlesource.com/#/c/10353/

Remove References to Apiary
https://widevine-internal-review.googlesource.com/#/c/9924/

Delete oldest entry in usage table when full
bug: 15184824
https://widevine-internal-review.googlesource.com/#/c/10295/

Port DeviceFiles to iOS.
https://widevine-internal-review.googlesource.com/#/c/10355/

Make testing functions in DeviceFiles private.
https://widevine-internal-review.googlesource.com/#/c/10354/

Add RSA encryption to haystack
https://widevine-internal-review.googlesource.com/#/c/10280/

Add string and vector includes to CDM header.
https://widevine-internal-review.googlesource.com/#/c/10352/

First version of oemcrypto logging
https://widevine-internal-review.googlesource.com/#/c/10252/

Update Names of Secure Stop Methods
bug: 11987015
https://widevine-internal-review.googlesource.com/#/c/10152/

Adjust timing on the Usage Table unit test
https://widevine-internal-review.googlesource.com/#/c/10307/

Fix all compiler warnings in CDM source release.
https://widevine-internal-review.googlesource.com/#/c/10293/

Fix memset bug: args in wrong order
https://widevine-internal-review.googlesource.com/#/c/10292/

Partial revert of 'Remove refs to test prov server, Level3 support...'
https://widevine-internal-review.googlesource.com/#/c/10281/

Pack structure OEMCrypto_PST_Report
https://widevine-internal-review.googlesource.com/#/c/10243/

Remove refs to test prov server, Level3 support; remove dead code
https://widevine-internal-review.googlesource.com/#/c/10220/

Partial revert of 'Document data strings; clean up license server parameters.'
https://widevine-internal-review.googlesource.com/#/c/10188/

Document data strings; clean up license server parameters.
https://widevine-internal-review.googlesource.com/#/c/10120/

Fix broken build after partner branch merge.
https://widevine-internal-review.googlesource.com/#/c/10181/

TODO Cleanup - core/src, core/include
https://widevine-internal-review.googlesource.com/#/c/9965/

TODO Cleanup - cdm, chromium, core/test.
https://widevine-internal-review.googlesource.com/#/c/9419/

Remove unneeded properties.
https://widevine-internal-review.googlesource.com/#/c/10162/

Change-Id: If2bb9d743a562a3875bebb91933c0aaadea286b2
This commit is contained in:
Fred Gylys-Colwell
2014-06-25 13:02:54 -07:00
parent 8a8feb747c
commit b5e8b87fed
66 changed files with 2927 additions and 1998 deletions

View File

@@ -34,13 +34,9 @@ wvcdm::ConfigTestEnv* g_config = NULL;
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;
bool g_use_chunked_transfer = false;
bool g_use_full_path = false;
bool g_use_secure_transfer = false;
wvcdm::LicenseServerId g_license_server_id =
wvcdm::kYouTubeContentProtectionServer;
wvcdm::kContentProtectionServer;
std::string kServiceCertificate =
"0803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010"
@@ -393,8 +389,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
session_sharing_id_(0) {}
virtual ~TestWvCdmClientPropertySet() {}
virtual std::string security_level() const { return security_level_; }
virtual std::vector<uint8_t> service_certificate() const {
virtual const std::string& security_level() const { return security_level_; }
virtual const std::string& service_certificate() const {
return service_certificate_;
}
virtual bool use_privacy_mode() const { return use_privacy_mode_; }
@@ -409,8 +405,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
security_level_ = security_level;
}
}
void set_service_certificate(
const std::vector<uint8_t>& service_certificate) {
void set_service_certificate(const std::string& service_certificate) {
service_certificate_ = service_certificate;
}
void set_use_privacy_mode(bool use_privacy_mode) {
@@ -423,7 +418,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
private:
std::string security_level_;
std::vector<uint8_t> service_certificate_;
std::string service_certificate_;
bool use_privacy_mode_;
bool is_session_sharing_enabled_;
uint32_t session_sharing_id_;
@@ -450,6 +445,19 @@ class WvCdmRequestLicenseTest : public testing::Test {
~WvCdmRequestLicenseTest() {}
protected:
void GetOfflineConfiguration(std::string* key_id, std::string* client_auth) {
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id->assign(wvcdm::a2bs_hex(config.key_id()));
else
key_id->assign(g_key_id);
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth->assign(config.client_auth());
else
client_auth->assign(g_client_auth);
}
void GenerateKeyRequest(const std::string& init_data,
CdmLicenseType license_type) {
wvcdm::CdmAppParameterMap app_parameters;
@@ -492,8 +500,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
std::string GetKeyRequestResponse(const std::string& server_url,
const std::string& client_auth) {
// Use secure connection and chunk transfer coding.
UrlRequest url_request(server_url + client_auth, g_port,
g_use_secure_transfer, g_use_chunked_transfer);
UrlRequest url_request(server_url + client_auth);
if (!url_request.is_connected()) {
return "";
}
@@ -517,7 +524,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
// the HTTP response.
std::string GetCertRequestResponse(const std::string& server_url) {
// Use secure connection and chunk transfer coding.
UrlRequest url_request(server_url, kDefaultHttpsPort, true, true);
UrlRequest url_request(server_url);
if (!url_request.is_connected()) {
return "";
}
@@ -538,8 +545,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
const std::string& client_auth,
const std::string& usage_info_request) {
// Use secure connection and chunk transfer coding.
UrlRequest url_request(server_url + client_auth, g_port,
g_use_secure_transfer, g_use_chunked_transfer);
UrlRequest url_request(server_url + client_auth);
if (!url_request.is_connected()) {
return "";
}
@@ -587,6 +593,20 @@ class WvCdmRequestLicenseTest : public testing::Test {
return itr->second;
}
CdmSecurityLevel GetDefaultSecurityLevel() {
std::string level = GetSecurityLevel(NULL).c_str();
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) == 0) {
security_level = kSecurityLevelL1;
} else if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
security_level = kSecurityLevelL3;
} else {
EXPECT_TRUE(false);
}
return security_level;
}
wvcdm::WvContentDecryptionModule decryptor_;
CdmKeyMessage key_msg_;
CdmSessionId session_id_;
@@ -614,6 +634,20 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
decryptor_.CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) {
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::string certificate;
std::string wrapped_private_key;
EXPECT_TRUE(handle.RetrieveCertificate(&certificate, &wrapped_private_key));
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(security_level));
EXPECT_FALSE(handle.RetrieveCertificate(&certificate, &wrapped_private_key));
}
TEST_F(WvCdmRequestLicenseTest, ProvisioningRetryTest) {
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
std::string provisioning_server_url;
@@ -710,16 +744,20 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
property_set_Ln.set_security_level("");
decryptor_.OpenSession(g_key_system, &property_set_Ln, &session_id_Ln);
std::string security_level = Properties::GetSecurityLevel(session_id_L1);
std::string security_level;
EXPECT_TRUE(Properties::GetSecurityLevel(session_id_L1, &security_level));
EXPECT_TRUE(!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
EXPECT_TRUE(Properties::UsePrivacyMode(session_id_L1));
EXPECT_EQ(Properties::GetSecurityLevel(session_id_L3),
QUERY_VALUE_SECURITY_LEVEL_L3);
EXPECT_TRUE(Properties::GetSecurityLevel(session_id_L3, &security_level));
EXPECT_EQ(security_level, QUERY_VALUE_SECURITY_LEVEL_L3);
EXPECT_FALSE(Properties::UsePrivacyMode(session_id_L3));
security_level = Properties::GetSecurityLevel(session_id_Ln);
EXPECT_TRUE(Properties::GetSecurityLevel(session_id_Ln, &security_level));
EXPECT_TRUE(security_level.empty() ||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
decryptor_.CloseSession(session_id_L1);
decryptor_.CloseSession(session_id_L3);
decryptor_.CloseSession(session_id_Ln);
@@ -776,7 +814,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeWithServiceCertificateTest) {
TestWvCdmClientPropertySet property_set;
property_set.set_use_privacy_mode(true);
property_set.set_service_certificate(a2b_hex(kServiceCertificate));
property_set.set_service_certificate(a2bs_hex(kServiceCertificate));
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
@@ -797,8 +835,7 @@ TEST_F(WvCdmRequestLicenseTest, WrongMessageTest) {
GenerateKeyRequest(wrong_message, kLicenseTypeStreaming);
// We should receive a response with no license, i.e. the extracted license
// response message should be empty or an HTTP error
UrlRequest url_request(g_license_server + g_client_auth, g_port,
g_use_secure_transfer, g_use_chunked_transfer);
UrlRequest url_request(g_license_server + g_client_auth);
if (!url_request.is_connected()) {
return;
}
@@ -828,14 +865,9 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) {
TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
// override default settings unless configured through the command line
std::string key_id = g_key_id;
std::string client_auth = g_client_auth;
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id.assign(wvcdm::a2bs_hex(config.key_id()));
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth.assign(config.client_auth());
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
@@ -845,14 +877,9 @@ TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
// override default settings unless configured through the command line
std::string key_id = g_key_id;
std::string client_auth = g_client_auth;
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id.assign(wvcdm::a2bs_hex(config.key_id()));
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth.assign(config.client_auth());
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
@@ -870,14 +897,9 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
// override default settings unless configured through the command line
std::string key_id = g_key_id;
std::string client_auth = g_client_auth;
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id.assign(wvcdm::a2bs_hex(config.key_id()));
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth.assign(config.client_auth());
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
@@ -902,14 +924,9 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
// override default settings unless configured through the command line
std::string key_id = g_key_id;
std::string client_auth = g_client_auth;
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id.assign(wvcdm::a2bs_hex(config.key_id()));
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth.assign(config.client_auth());
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
@@ -954,14 +971,9 @@ TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewal) {
TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
// override default settings unless configured through the command line
std::string key_id = g_key_id;
std::string client_auth = g_client_auth;
ConfigTestEnv config(g_license_server_id, false);
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
key_id.assign(wvcdm::a2bs_hex(config.key_id()));
if (g_client_auth.compare(g_config->client_auth()) == 0)
client_auth.assign(config.client_auth());
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
@@ -979,19 +991,10 @@ class WvCdmUsageInfoTest
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
TEST_P(WvCdmUsageInfoTest, DISABLED_UsageInfo) {
File file;
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
std::string level = GetSecurityLevel(NULL).c_str();
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) == 0) {
security_level = kSecurityLevelL1;
} else if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
security_level = kSecurityLevelL3;
} else {
EXPECT_TRUE(false);
}
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteUsageInfo());
@@ -1037,7 +1040,11 @@ TEST_P(WvCdmUsageInfoTest, DISABLED_UsageInfo) {
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
}
status = decryptor_.GetUsageInfo(&usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
switch (status) {
case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break;
case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break;
default: FAIL() << "GetUsageInfo failed with error " << status ; break;
}
}
}
@@ -1499,14 +1506,14 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
}
TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
const std::string kYtCpKeyId = a2bs_hex(
const std::string kCpKeyId = a2bs_hex(
"000000347073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id
"0801121030313233343536373839616263646566"); // pssh data
SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry;
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
if (data->retrieve_key) {
GenerateKeyRequest(kYtCpKeyId, kLicenseTypeStreaming);
GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
}
@@ -1579,10 +1586,6 @@ void show_menu(char* prog_name) {
std::cout << " or adb shell '" << prog_name << " -u\"url\"'" << std::endl
<< std::endl;
std::cout << std::setw(35) << std::left << " -c/--chunked_transfer";
std::cout << "specifies chunked transfer encoding in request" << std::endl
<< std::endl;
std::cout << std::setw(35) << std::left << " -f/--use_full_path";
std::cout << "specify server url is not a proxy server" << std::endl;
std::cout << std::endl;
@@ -1592,7 +1595,7 @@ void show_menu(char* prog_name) {
std::cout << std::setw(35) << std::left << " ";
std::cout << "gp (case sensitive) for GooglePlay server" << std::endl;
std::cout << std::setw(35) << std::left << " ";
std::cout << "cp (case sensitive) for Youtube Content Protection server"
std::cout << "cp (case sensitive) for Content Protection server"
<< std::endl << std::endl;
std::cout << std::setw(35) << std::left << " -k/--keyid=<key_id>";
@@ -1616,34 +1619,22 @@ int main(int argc, char** argv) {
bool show_usage = false;
static const struct option long_options[] = {
{"chunked_transfer", no_argument, NULL, 'c'},
{"keyid", required_argument, NULL, 'k'},
{"license_server_id", required_argument, NULL, 'i'},
{"license_server_url", required_argument, NULL, 'u'},
{"port", required_argument, NULL, 'p'},
{"secure_transfer", no_argument, NULL, 's'},
{"use_full_path", no_argument, NULL, 'f'},
{NULL, 0, NULL, '\0'}};
int option_index = 0;
int opt = 0;
while ((opt = getopt_long(argc, argv, "cfi:k:p:su:", long_options,
while ((opt = getopt_long(argc, argv, "i:k:u:", long_options,
&option_index)) != -1) {
switch (opt) {
case 'c': {
g_use_chunked_transfer = true;
break;
}
case 'f': {
g_use_full_path = true;
break;
}
case 'i': {
std::string license_id(optarg);
if (!license_id.compare("gp")) {
g_license_server_id = wvcdm::kGooglePlayServer;
} else if (!license_id.compare("cp")) {
g_license_server_id = wvcdm::kYouTubeContentProtectionServer;
g_license_server_id = wvcdm::kContentProtectionServer;
} else {
std::cout << "Invalid license server id" << optarg << std::endl;
show_usage = true;
@@ -1655,15 +1646,6 @@ int main(int argc, char** argv) {
g_key_id.assign(optarg);
break;
}
case 'p': {
g_port.clear();
g_port.assign(optarg);
break;
}
case 's': {
g_use_secure_transfer = true;
break;
}
case 'u': {
g_license_server.clear();
g_license_server.assign(optarg);
@@ -1688,32 +1670,21 @@ int main(int argc, char** argv) {
// The following variables are configurable through command line
// options. If the command line arguments are absent, use the settings
// in license_servers[] pointed to by g_config.
// in kLicenseServers[] pointed to by g_config.
if (g_key_id.empty()) {
g_key_id.assign(g_config->key_id());
}
if (g_license_server.empty()) {
g_license_server.assign(g_config->license_server());
}
if (g_port.empty()) {
g_port.assign(g_config->port());
}
if (!g_use_chunked_transfer) {
g_use_chunked_transfer = g_config->use_chunked_transfer();
}
if (!g_use_secure_transfer) {
g_use_secure_transfer = g_config->use_secure_transfer();
}
// Displays server url, port and key Id being used
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);
g_config->set_license_server(g_license_server);
g_config->set_port(g_port);
int status = RUN_ALL_TESTS();
delete g_config;

View File

@@ -8,10 +8,10 @@ namespace wvcdm {
namespace test_vectors {
// for FileStore unit tests
static const std::string kFileExists = "/system/bin/sh";
static const std::string kDirExists = "/system/bin";
static const std::string kFileDoesNotExist = "/system/bin/enoext";
static const std::string kDirDoesNotExist = "/system/bin_enoext";
static const std::string kExistentFile = "/system/bin/sh";
static const std::string kExistentDir = "/system/bin";
static const std::string kNonExistentFile = "/system/bin/enoext";
static const std::string kNonExistentDir = "/system/bin_enoext";
static const std::string kTestDir = "/data/mediadrm/IDM0/";
} // namespace test_vectors

View File

@@ -51,6 +51,8 @@ LOCAL_SHARED_LIBRARIES := \
libstlport \
libutils
LOCAL_CFLAGS += -DUNIT_TEST
# Needed to use gMock 1.7.0 on Android
LOCAL_CFLAGS += \
-DGTEST_HAS_TR1_TUPLE \