Enable SPOIDs in Treble Widevine Glue Layer
Adds code to the Widevine Glue Layer that drives the generation and use of SPOIDs on platforms that support SPOIDs. (All devices whose first release is Android O or later.) Note that this only applies to the new, Treble-ized API. If the Widevine DRM Plugin is accessed through the old API, it will not use SPOIDs. This is by design because the old API does not provide an application package name, so SPOID generation is no better than the existing, origin-based solution. Bug: 27101531 Test: Unit tests Test: GTS tests Test: Google Play Change-Id: I80f79fca84065105e218e9070a1d5299c8e33500
This commit is contained in:
@@ -9,18 +9,22 @@
|
||||
#include "WVDrmPlugin.h"
|
||||
#include "TypeConvert.h"
|
||||
|
||||
#include "cutils/properties.h"
|
||||
#include "mapErrors-inl.h"
|
||||
#include "media/stagefright/MediaErrors.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "utils/List.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
static const char* const kResetSecurityLevel = "";
|
||||
static const char* const kEnable = "enable";
|
||||
static const char* const kDisable = "disable";
|
||||
static const std::string kPsshTag = "pssh";
|
||||
static const char* const kSpecialUnprovisionResponse = "unprovision";
|
||||
}
|
||||
|
||||
static const char* const kResetSecurityLevel = "";
|
||||
static const char* const kEnable = "enable";
|
||||
static const char* const kDisable = "disable";
|
||||
static const std::string kPsshTag = "pssh";
|
||||
static const char* const kSpecialUnprovisionResponse = "unprovision";
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
@@ -102,11 +106,15 @@ KeyStatusType ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus) {
|
||||
WVDrmPlugin::WVDrmPlugin(const sp<WvContentDecryptionModule>& cdm,
|
||||
const std::string& appPackageName,
|
||||
WVGenericCryptoInterface* crypto)
|
||||
: mAppPackageName(appPackageName),
|
||||
mCDM(cdm),
|
||||
mCdmIdentifier(kDefaultCdmIdentifier),
|
||||
: mCDM(cdm),
|
||||
mCrypto(crypto),
|
||||
mCryptoSessions() {}
|
||||
mCryptoSessions() {
|
||||
mCdmIdentifierBuilder.set_app_package_name(appPackageName);
|
||||
|
||||
std::string deviceId;
|
||||
queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, deviceId);
|
||||
mCdmIdentifierBuilder.set_device_id(deviceId);
|
||||
}
|
||||
|
||||
WVDrmPlugin::~WVDrmPlugin() {
|
||||
typedef map<CdmSessionId, CryptoSession>::iterator mapIterator;
|
||||
@@ -127,7 +135,8 @@ Return<void> WVDrmPlugin::openSession(openSession_cb _hidl_cb) {
|
||||
|
||||
CdmSessionId cdmSessionId;
|
||||
CdmResponseType res =
|
||||
mCDM->OpenSession("com.widevine", &mPropertySet, mCdmIdentifier, this,
|
||||
mCDM->OpenSession("com.widevine", &mPropertySet,
|
||||
mCdmIdentifierBuilder.get_identifier(), this,
|
||||
&cdmSessionId);
|
||||
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
@@ -269,8 +278,8 @@ Return<void> WVDrmPlugin::getKeyRequest(
|
||||
CdmKeyRequest keyRequest;
|
||||
CdmResponseType res = mCDM->GenerateKeyRequest(
|
||||
cdmSessionId, cdmKeySetId, cdmInitDataType, processedInitData,
|
||||
cdmLicenseType, cdmParameters, &mPropertySet, mCdmIdentifier,
|
||||
&keyRequest);
|
||||
cdmLicenseType, cdmParameters, &mPropertySet,
|
||||
mCdmIdentifierBuilder.get_identifier(), &keyRequest);
|
||||
|
||||
requestType = ConvertFromCdmKeyRequestType(keyRequest.type);
|
||||
|
||||
@@ -412,11 +421,9 @@ Return<Status> WVDrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId,
|
||||
|
||||
std::string cdmCertAuthority = certificateAuthority;
|
||||
|
||||
CdmResponseType res = mCDM->GetProvisioningRequest(cdmCertType,
|
||||
cdmCertAuthority,
|
||||
mCdmIdentifier,
|
||||
&cdmProvisionRequest,
|
||||
&cdmDefaultUrl);
|
||||
CdmResponseType res = mCDM->GetProvisioningRequest(
|
||||
cdmCertType, cdmCertAuthority, mCdmIdentifierBuilder.get_identifier(),
|
||||
&cdmProvisionRequest, &cdmDefaultUrl);
|
||||
String8 defaultUrl;
|
||||
Vector<uint8_t> request;
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
@@ -440,21 +447,21 @@ Return<void> WVDrmPlugin::provideProvisionResponse(
|
||||
|
||||
CdmProvisioningResponse cdmResponse(resp.begin(), resp.end());
|
||||
if (cdmResponse == kSpecialUnprovisionResponse) {
|
||||
if (mCdmIdentifier == kDefaultCdmIdentifier) {
|
||||
if (mCdmIdentifierBuilder.get_identifier() == kDefaultCdmIdentifier) {
|
||||
_hidl_cb(toStatus(kErrorNoOriginSpecified), toHidlVec(certificate),
|
||||
toHidlVec(wrappedKey));
|
||||
return Void();
|
||||
}
|
||||
_hidl_cb(toStatus(unprovision(mCdmIdentifier)), toHidlVec(certificate),
|
||||
_hidl_cb(toStatus(unprovision(mCdmIdentifierBuilder.get_identifier())),
|
||||
toHidlVec(certificate),
|
||||
toHidlVec(wrappedKey));
|
||||
return Void();
|
||||
} else {
|
||||
std::string cdmCertificate;
|
||||
std::string cdmWrappedKey;
|
||||
CdmResponseType res = mCDM->HandleProvisioningResponse(mCdmIdentifier,
|
||||
cdmResponse,
|
||||
&cdmCertificate,
|
||||
&cdmWrappedKey);
|
||||
CdmResponseType res = mCDM->HandleProvisioningResponse(
|
||||
mCdmIdentifierBuilder.get_identifier(), cdmResponse, &cdmCertificate,
|
||||
&cdmWrappedKey);
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
certificate = StrToVector(cdmCertificate);
|
||||
wrappedKey = StrToVector(cdmWrappedKey);
|
||||
@@ -594,7 +601,7 @@ Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
|
||||
} else if (name == "appId") {
|
||||
value = mPropertySet.app_id().c_str();
|
||||
} else if (name == "origin") {
|
||||
value = mCdmIdentifier.origin.c_str();
|
||||
value = mCdmIdentifierBuilder.origin().c_str();
|
||||
} else {
|
||||
ALOGE("App requested unknown string property %s", name.string());
|
||||
status = android::ERROR_DRM_CANNOT_HANDLE;
|
||||
@@ -613,7 +620,7 @@ Return<void> WVDrmPlugin::getPropertyByteArray(
|
||||
Vector<uint8_t> value;
|
||||
|
||||
if (name == "deviceUniqueId") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, value);
|
||||
value = StrToVector(mCdmIdentifierBuilder.get_device_unique_id());
|
||||
} else if (name == "provisioningUniqueId") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, value);
|
||||
} else if (name == "serviceCertificate") {
|
||||
@@ -696,7 +703,9 @@ Return<Status> WVDrmPlugin::setPropertyString(const hidl_string& propertyName,
|
||||
ALOGE("App tried to set the origin while sessions are opened.");
|
||||
return toStatus(kErrorSessionIsOpen);
|
||||
} else {
|
||||
mCdmIdentifier.origin = _value.string();
|
||||
if (!mCdmIdentifierBuilder.set_origin(_value.string())) {
|
||||
return Status::BAD_VALUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ALOGE("App set unknown string property %s", name.string());
|
||||
@@ -1242,6 +1251,70 @@ status_t WVDrmPlugin::unprovision(const CdmIdentifier& identifier) {
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for the CdmIdentifierBuilder inner class
|
||||
WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder()
|
||||
: mCdmIdentifier(),
|
||||
mIsIdentifierSealed(false),
|
||||
mDeviceId(),
|
||||
mAppPackageName() {
|
||||
// Determine if this device supports SPOIDs.
|
||||
int32_t firstApiLevel = property_get_int32("ro.product.first_api_level", 0);
|
||||
if (firstApiLevel == 0) {
|
||||
// First API Level is 0 on factory ROMs, but we can assume the current SDK
|
||||
// version is the first if it's a factory ROM.
|
||||
firstApiLevel = property_get_int32("ro.build.version.sdk", 0);
|
||||
}
|
||||
// TODO(juce): b/34548395 Make sure this API version is correct.
|
||||
mUseSpoid = firstApiLevel >= 26; // Android O
|
||||
}
|
||||
|
||||
const CdmIdentifier& WVDrmPlugin::CdmIdentifierBuilder::get_identifier() {
|
||||
if (!mIsIdentifierSealed) calculateSpoid();
|
||||
mIsIdentifierSealed = true;
|
||||
return mCdmIdentifier;
|
||||
}
|
||||
|
||||
const std::string& WVDrmPlugin::CdmIdentifierBuilder::get_device_unique_id() {
|
||||
if (mUseSpoid) {
|
||||
return get_identifier().spoid;
|
||||
} else {
|
||||
return mDeviceId;
|
||||
}
|
||||
}
|
||||
|
||||
bool WVDrmPlugin::CdmIdentifierBuilder::set_device_id(const std::string& id) {
|
||||
if (mIsIdentifierSealed) return false;
|
||||
mDeviceId = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WVDrmPlugin::CdmIdentifierBuilder::set_app_package_name(const std::string& id) {
|
||||
if (mIsIdentifierSealed) return false;
|
||||
mAppPackageName = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) {
|
||||
if (mIsIdentifierSealed) return false;
|
||||
mCdmIdentifier.origin = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() {
|
||||
if (mUseSpoid) {
|
||||
uint8_t hash[SHA256_DIGEST_LENGTH];
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, mDeviceId.data(), mDeviceId.length());
|
||||
SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length());
|
||||
SHA256_Update(&ctx, origin().data(), origin().length());
|
||||
SHA256_Final(hash, &ctx);
|
||||
|
||||
mCdmIdentifier.spoid =
|
||||
std::string(reinterpret_cast<char*>(hash), SHA256_DIGEST_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
|
||||
Reference in New Issue
Block a user