diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index fdb1a060..ef5a0df6 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "cdm_client_property_set.h" #include "gmock/gmock.h" @@ -116,16 +117,19 @@ const std::string kAppId("com.unittest.mock.app.id"); const uint8_t* const kUnprovisionResponse = reinterpret_cast("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 { @@ -433,7 +437,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. @@ -842,8 +846,6 @@ TEST_F(WVDrmPluginTest, UnprovisionsOrigin) { StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -867,16 +869,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> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + std::vector 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 /* cert */, + hidl_vec /* key */) { + EXPECT_EQ(Status::OK, status); + }); +} + +TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOriginOrSpoid) { android::sp> cdm = new StrictMock(); StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -898,8 +922,6 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { StrictMock crypto; std::string appPackageName; - std::vector cert; - std::vector key; std::vector specialResponse; specialResponse.assign( kUnprovisionResponse, kUnprovisionResponse + kUnprovisionResponseSize); @@ -1052,7 +1074,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"; @@ -1069,7 +1090,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, _)) @@ -1133,36 +1154,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 vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector 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 vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector id(vectorResult); EXPECT_THAT(id, ElementsAreArray(provisioningId.data(), @@ -1171,21 +1192,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()); }); @@ -1206,7 +1227,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { plugin.getPropertyByteArray( hidl_string("metrics"), - [&](Status status, hidl_vec vectorResult) { + [&](Status status, hidl_vec vectorResult) { ASSERT_EQ(Status::OK, status); std::vector id(vectorResult); EXPECT_THAT(id, ElementsAreArray(serializedMetrics.data(), @@ -1262,6 +1283,117 @@ TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) { ASSERT_NE(Status::OK, status); } +TEST_F(WVDrmPluginTest, CompliesWithSpoidVariability) { + StrictMock 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 + spoids[kDeviceCount][kAppCount][kOriginCount][kPluginCount]; + + for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) { + const std::string& deviceId = kDeviceIds[deviceIndex]; + + android::sp> cdm = new StrictMock(); + + 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 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& 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& 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> cdm = new StrictMock(); StrictMock crypto;