Merges to android Pi release (part 7)
These are a set of CLs merged from the wv cdm repo to the android repo. * Resolve intermittent decrypt error. Author: Jeff Fore <jfore@google.com> [ Merge of http://go/wvgerrit/35720 ] The CdmSession's closed state was not properly initialized resulting in intermittent SESSION_NOT_FOUND_FOR_DECRYPT errors. In CdmEngine::Decrypt the session is looked up by the key id. A list of open sessions is acquired by calling CdmSessionMap::GetSessionList and each session in the list is queried to see if it has the key. In building the list in CdmSessionMap::GetSessionList, sessions are only added to the query list *if* the session is not closed. The closed status was not initialized and during testing the query list would not contain the session causing CdmEngine::Decrypt to return SESSION_NOT_FOUND_FOR_DECRYPT resulting in the ce cdm api returning widevine::Cdm::kNoKey. * No support for pre- C++11 compilation. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/35381 ] * Handle unaligned nonce pointer in RewrapDeviceRSAKey calls. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/35340 ] The pointer points into a message and it may not be aligned. Always copy the nonce into aligned memory before checking it. BUG: 38140370 Add note to CHANGELOG for this. * Compiler strictness: more checks and code cleanup. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/35300 ] Use the switches proposed in b/38033653 (as much as possible - some conflicts with protobufs and gtest prevent fully accepting them). Switch to clang for x32 build; ensure that both x86-64 and x86-32 builds compile and link cleanly. BUG: 38032429 BUG: 38033653 This partially resolves b/38458986 * Android build fixes Author: Rahul Frias <rfrias@google.com> [ Merge of http://go/wvgerrit/35102 ] These corrections address compile warnings and errors for android and unit tests. * Embedded License: Add sub license key sessions. Author: Jeff Fore <jfore@google.com> [ Merge of http://go/wvgerrit/33680 ] NOTE: this adds the AddSubSession() method, but it is not yet being used. Use and proper cleanup is in an upcoming CL. * Embedded license: Add track label field. Author: Jeff Fore <jfore@google.com> [ Merge of http://go/wvgerrit/33660 ] A new track label field (a string) is added to the key container and the sub session data objects. This field will be used in handling sub license requests. * Embedded license: extract keys from init_data. Author: Jeff Fore <jfore@google.com> [ Merge of http://go/wvgerrit/33621 ] * Embedded license: add protobuf messages. Author: Jeff Fore <jfore@google.com> [ Merge of http://go/wvgerrit/33620 ] also sync the widevine header definition with recent naming changes. * Improve handling of provisioning response errors. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/33600 ] Separate out the case of no response and the case where the message is believed to be a JSON+base64 message but it doesn't parse properly. BUG: 71650075 Test: Not currently passing. Will be addressed in a subsequent commit in the chain. Change-Id: I3c86f1c54980b071aec7461ac58541836551f896
This commit is contained in:
@@ -88,10 +88,6 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libwvlevel3 \
|
||||
libwvdrmdrmplugin_hidl \
|
||||
|
||||
# When the GNU linker sees a library, it discards all symbols that it doesn't
|
||||
# need. libhidl_utils must come after libwvdrmdrmplugin.
|
||||
LOCAL_STATIC_LIBRARIES += libhidl_utils
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "cdm_client_property_set.h"
|
||||
#include "gmock/gmock.h"
|
||||
@@ -117,16 +118,19 @@ const std::string kAppId("com.unittest.mock.app.id");
|
||||
const uint8_t* const kUnprovisionResponse =
|
||||
reinterpret_cast<const uint8_t*>("unprovision");
|
||||
const size_t kUnprovisionResponseSize = 11;
|
||||
const std::string kDeviceId = "0123456789ABCDEF";
|
||||
const std::string kDeviceId("0123456789\0ABCDEF", 17);
|
||||
|
||||
// This is a serialized MetricsGroup message containing a small amount of
|
||||
// sample data. This ensures we're able to extract it via a property.
|
||||
const char kSerializedMetrics[] = {
|
||||
0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00,
|
||||
0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05,
|
||||
0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73,
|
||||
0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65};
|
||||
0x0a, 0x0a, 0x0a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x12, 0x02, 0x08, 0x00,
|
||||
0x0a, 0x12, 0x0a, 0x05, 0x74, 0x65, 0x73, 0x74, 0x32, 0x12, 0x09, 0x11,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x15, 0x0a, 0x05,
|
||||
0x74, 0x65, 0x73, 0x74, 0x33, 0x12, 0x0c, 0x1a, 0x0a, 0x74, 0x65, 0x73,
|
||||
0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65
|
||||
};
|
||||
|
||||
#define N_ELEM(a) (sizeof(a)/sizeof(a[0]))
|
||||
} // anonymous namespace
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
@@ -434,7 +438,7 @@ TEST_F(WVDrmPluginTest, DISABLED_GeneratesKeyRequests) {
|
||||
{kIsoBmffMimeType, initData, cdmPsshBox}, // ISO-BMFF, old passing style
|
||||
{kWebmMimeType, initData, cdmInitData} // WebM
|
||||
};
|
||||
size_t testSetCount = sizeof(testSets) / sizeof(TestSet);
|
||||
size_t testSetCount = N_ELEM(testSets);
|
||||
|
||||
// Set up the expected calls. Per gMock rules, this must be done for all test
|
||||
// sets prior to testing any of them.
|
||||
@@ -809,8 +813,8 @@ TEST_F(WVDrmPluginTest, UnprovisionsDevice) {
|
||||
.Times(1);
|
||||
|
||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||
status_t res = plugin.unprovisionDevice();
|
||||
ASSERT_EQ(android::OK, res);
|
||||
Status res = plugin.unprovisionDevice();
|
||||
ASSERT_EQ(Status::OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, MuxesUnprovisioningErrors) {
|
||||
@@ -830,12 +834,12 @@ TEST_F(WVDrmPluginTest, MuxesUnprovisioningErrors) {
|
||||
.WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR));
|
||||
|
||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||
status_t res = plugin.unprovisionDevice();
|
||||
ASSERT_NE(android::OK, res);
|
||||
Status res = plugin.unprovisionDevice();
|
||||
ASSERT_NE(Status::OK, res);
|
||||
res = plugin.unprovisionDevice();
|
||||
ASSERT_NE(android::OK, res);
|
||||
ASSERT_NE(Status::OK, res);
|
||||
res = plugin.unprovisionDevice();
|
||||
ASSERT_NE(android::OK, res);
|
||||
ASSERT_NE(Status::OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
|
||||
@@ -843,8 +847,6 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
|
||||
StrictMock<MockCrypto> crypto;
|
||||
std::string appPackageName;
|
||||
|
||||
std::vector<uint8_t> cert;
|
||||
std::vector<uint8_t> key;
|
||||
std::vector<uint8_t> specialResponse;
|
||||
specialResponse.assign(
|
||||
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
|
||||
@@ -868,16 +870,38 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOrigin) {
|
||||
// This test is only valid on SPOID-free devices. SPOID devices can
|
||||
// unprovision without an origin because the empty-origin provisioning is
|
||||
// not global.
|
||||
TEST_F(WVDrmPluginTest, UnprovisionsGloballyWithSpoid) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
StrictMock<MockCrypto> crypto;
|
||||
std::string appPackageName;
|
||||
|
||||
std::vector<uint8_t> specialResponse;
|
||||
specialResponse.assign(
|
||||
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(kDeviceId),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN)))
|
||||
.Times(1);
|
||||
EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN)))
|
||||
.Times(1);
|
||||
|
||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true);
|
||||
plugin.provideProvisionResponse(
|
||||
toHidlVec(specialResponse),
|
||||
[&](Status status, hidl_vec<uint8_t> /* cert */,
|
||||
hidl_vec<uint8_t> /* key */) {
|
||||
EXPECT_EQ(Status::OK, status);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOriginOrSpoid) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
StrictMock<MockCrypto> crypto;
|
||||
std::string appPackageName;
|
||||
|
||||
std::vector<uint8_t> cert;
|
||||
std::vector<uint8_t> key;
|
||||
std::vector<uint8_t> specialResponse;
|
||||
specialResponse.assign(
|
||||
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
|
||||
@@ -899,8 +923,6 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) {
|
||||
StrictMock<MockCrypto> crypto;
|
||||
std::string appPackageName;
|
||||
|
||||
std::vector<uint8_t> cert;
|
||||
std::vector<uint8_t> key;
|
||||
std::vector<uint8_t> specialResponse;
|
||||
specialResponse.assign(
|
||||
kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize);
|
||||
@@ -1053,7 +1075,6 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
CdmQueryMap l3Map;
|
||||
l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
|
||||
static const std::string deviceId("0123456789\0ABCDEF", 17);
|
||||
static const std::string systemId = "The Universe";
|
||||
static const std::string provisioningId("Life\0&Everything", 16);
|
||||
static const std::string openSessions = "42";
|
||||
@@ -1074,7 +1095,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(deviceId),
|
||||
.WillOnce(DoAll(SetArgPointee<2>(kDeviceId),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SYSTEM_ID, _))
|
||||
@@ -1142,36 +1163,36 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("securityLevel"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("securityLevel"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyByteArray(
|
||||
hidl_string("deviceUniqueId"),
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
std::vector<uint8_t> id(vectorResult);
|
||||
EXPECT_THAT(id, ElementsAreArray(deviceId.data(), deviceId.size()));
|
||||
EXPECT_THAT(id, ElementsAreArray(kDeviceId.data(), kDeviceId.size()));
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("systemId"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(systemId.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyByteArray(
|
||||
hidl_string("provisioningUniqueId"),
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
std::vector<uint8_t> id(vectorResult);
|
||||
EXPECT_THAT(id, ElementsAreArray(provisioningId.data(),
|
||||
@@ -1180,21 +1201,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("numberOfOpenSessions"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_EQ(openSessions, stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("maxNumberOfSessions"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_EQ(maxSessions, stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("oemCryptoApiVersion"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.c_str());
|
||||
});
|
||||
@@ -1215,7 +1236,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
|
||||
plugin.getPropertyByteArray(
|
||||
hidl_string("metrics"),
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
std::vector<uint8_t> id(vectorResult);
|
||||
EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(),
|
||||
@@ -1271,6 +1292,117 @@ TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) {
|
||||
ASSERT_NE(Status::OK, status);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, CompliesWithSpoidVariability) {
|
||||
StrictMock<MockCrypto> crypto;
|
||||
|
||||
const std::string kDeviceIds[] = {
|
||||
kDeviceId,
|
||||
kDeviceId + " the Second",
|
||||
};
|
||||
const size_t kDeviceCount = N_ELEM(kDeviceIds);
|
||||
|
||||
const std::string kAppNames[] = {
|
||||
std::string("com.google.widevine"),
|
||||
std::string("com.youtube"),
|
||||
};
|
||||
const size_t kAppCount = N_ELEM(kAppNames);
|
||||
|
||||
const std::string kOrigins[] = {
|
||||
kOrigin,
|
||||
kOrigin + " but not that one, the other one.",
|
||||
std::string(/* Intentionally Empty */),
|
||||
};
|
||||
const size_t kOriginCount = N_ELEM(kOrigins);
|
||||
|
||||
const size_t kPluginCount = 2;
|
||||
|
||||
const size_t kPluginsPerCdm = kAppCount * kOriginCount * kPluginCount;
|
||||
|
||||
// We will get kPluginCount SPOIDs for every app package name + device id +
|
||||
// origin combination.
|
||||
std::vector<uint8_t>
|
||||
spoids[kDeviceCount][kAppCount][kOriginCount][kPluginCount];
|
||||
|
||||
for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) {
|
||||
const std::string& deviceId = kDeviceIds[deviceIndex];
|
||||
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _))
|
||||
.Times(AtLeast(kPluginsPerCdm))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(deviceId),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) {
|
||||
const std::string& appPackageName = kAppNames[appIndex];
|
||||
|
||||
for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) {
|
||||
const std::string& origin = kOrigins[originIndex];
|
||||
|
||||
for (size_t pluginIndex = 0;
|
||||
pluginIndex < kPluginCount;
|
||||
++pluginIndex) {
|
||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true);
|
||||
|
||||
if (!origin.empty()) {
|
||||
ASSERT_EQ(Status::OK,
|
||||
plugin.setPropertyString(hidl_string("origin"),
|
||||
hidl_string(origin)));
|
||||
}
|
||||
|
||||
plugin.getPropertyByteArray(
|
||||
hidl_string("deviceUniqueId"),
|
||||
[&](Status status, hidl_vec<uint8_t> vectorResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
spoids[deviceIndex][appIndex][originIndex][pluginIndex] =
|
||||
vectorResult;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This nest of loops makes sure all the SPOIDs we retrieved above are
|
||||
// identical if their parameters were identical and dissimilar otherwise.
|
||||
for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) {
|
||||
for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) {
|
||||
for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) {
|
||||
for (size_t pluginIndex = 0;
|
||||
pluginIndex < kPluginCount;
|
||||
++pluginIndex) {
|
||||
const std::vector<uint8_t>& firstSpoid =
|
||||
spoids[deviceIndex][appIndex][originIndex][pluginIndex];
|
||||
|
||||
for (size_t deviceIndex2 = 0;
|
||||
deviceIndex2 < kDeviceCount;
|
||||
++deviceIndex2) {
|
||||
for (size_t appIndex2 = 0; appIndex2 < kAppCount; ++appIndex2) {
|
||||
for (size_t originIndex2 = 0;
|
||||
originIndex2 < kOriginCount;
|
||||
++originIndex2) {
|
||||
for (size_t pluginIndex2 = 0;
|
||||
pluginIndex2 < kPluginCount;
|
||||
++pluginIndex2) {
|
||||
const std::vector<uint8_t>& secondSpoid =
|
||||
spoids[deviceIndex2][appIndex2][originIndex2][pluginIndex2];
|
||||
|
||||
if (deviceIndex == deviceIndex2 &&
|
||||
appIndex == appIndex2 &&
|
||||
originIndex == originIndex2) {
|
||||
EXPECT_EQ(firstSpoid, secondSpoid);
|
||||
} else {
|
||||
EXPECT_NE(firstSpoid, secondSpoid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, FailsGenericMethodsWithoutAnAlgorithmSet) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
StrictMock<MockCrypto> crypto;
|
||||
@@ -2235,7 +2367,7 @@ TEST_F(WVDrmPluginTest, CanSetSessionSharing) {
|
||||
}
|
||||
|
||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||
status_t res;
|
||||
Status res;
|
||||
|
||||
// Test turning on session sharing
|
||||
Status status = plugin.setPropertyString(hidl_string("sessionSharing"),
|
||||
|
||||
Reference in New Issue
Block a user