Files
android/libwvdrmengine/src_hidl/WVDrmFactory.cpp
Alex Dale fb847c4704 Query analog output capabilities.
[ Merge of http://go/wvgerrit/107763 ]

This CL enables the ability to query the CDM for the analog output
capabilites of the device.  Due to the number of possibilities that
OEMCrypto can report, two queries are exposed:
- Output capabilities: None, Supported, CGMS-C, Unknown
- Can disable: True, False, Unknown

Bug: 168322023
Test: Android integration test
Change-Id: I8036a89237d698f170d2c1901c41d1d6b708c917
2020-10-15 17:46:13 -07:00

276 lines
9.2 KiB
C++

//
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
//#define LOG_NDEBUG 0
#define LOG_TAG "WVCdm"
#include "WVDrmFactory.h"
#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
#include "HidlTypes.h"
#include "WVCDMSingleton.h"
#include "WVDrmPlugin.h"
#include "WVUUID.h"
#include "android-base/properties.h"
#include "cutils/properties.h"
#include "wv_cdm_constants.h"
#include "wv_content_decryption_module.h"
#include "wv_metrics.h"
namespace wvdrm {
namespace hardware {
namespace drm {
namespace V1_3 {
namespace widevine {
using wvdrm::hardware::drm::V1_2::widevine::WVDrmPlugin;
WVGenericCryptoInterface WVDrmFactory::sOemCryptoInterface;
Return<bool> WVDrmFactory::isCryptoSchemeSupported(
const hidl_array<uint8_t, 16>& uuid) {
return isWidevineUUID(uuid.data());
}
Return<bool> WVDrmFactory::isCryptoSchemeSupported_1_2(
const hidl_array<uint8_t, 16>& uuid, const hidl_string& initDataType,
SecurityLevel level) {
if (!isWidevineUUID(uuid.data()) || !isContentTypeSupported(initDataType)) {
return false;
}
if (wvcdm::WvContentDecryptionModule::IsSecurityLevelSupported(
wvcdm::kSecurityLevelL1)) {
if (wvcdm::WvContentDecryptionModule::IsAudio(initDataType)) {
if (level < SecurityLevel::HW_SECURE_ALL) {
return true;
}
} else {
return true;
}
}
return level <= SecurityLevel::SW_SECURE_DECODE;
}
Return<bool> WVDrmFactory::isContentTypeSupported(
const hidl_string& initDataType) {
return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.c_str());
}
Return<void> WVDrmFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid,
const hidl_string& appPackageName,
createPlugin_cb _hidl_cb) {
const auto& self = android::hardware::IPCThreadState::self();
const char* sid = self->getCallingSid();
sid = sid ? (strstr(sid, "mediadrmserver") ? sid : "app") : "nullptr";
ALOGI("[%s][%s] calling %s", sid, appPackageName.c_str(),
__PRETTY_FUNCTION__);
sp<IDrmPlugin> plugin;
if (!isCryptoSchemeSupported(uuid.data())) {
ALOGE(
"Widevine Drm HAL: failed to create drm plugin, "
"invalid crypto scheme");
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, plugin);
return Void();
}
if (!isBlankAppPackageNameAllowed() && appPackageName.empty()) {
ALOGE(
"Widevine Drm HAL: Failed to create DRM Plugin, blank App Package "
"Name disallowed.");
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, plugin);
return Void();
}
plugin = new WVDrmPlugin(getCDM(), appPackageName.c_str(),
&sOemCryptoInterface, areSpoidsEnabled());
android::hardware::setRequestingSid(plugin, true);
_hidl_cb(Status::OK, plugin);
return Void();
}
bool WVDrmFactory::areSpoidsEnabled() {
return firstApiLevel() >= 26; // Android O
}
bool WVDrmFactory::isBlankAppPackageNameAllowed() {
return firstApiLevel() < 29; // Android Q
}
int32_t WVDrmFactory::firstApiLevel() {
// Check what this device's first API level was.
int32_t firstApiLevel =
android::base::GetIntProperty<int32_t>("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 =
android::base::GetIntProperty<int32_t>("ro.build.version.sdk", 0);
}
return firstApiLevel;
}
Return<void> WVDrmFactory::getSupportedCryptoSchemes(
getSupportedCryptoSchemes_cb _hidl_cb) {
std::vector<hidl_array<uint8_t, 16>> schemes;
for (const auto& scheme : wvdrm::getSupportedCryptoSchemes()) {
schemes.push_back(scheme);
}
_hidl_cb(schemes);
return Void();
}
std::string WVDrmFactory::stringToHex(const std::string& input) {
// If input contains punctuations that are not part of
// a valid server url, we need to convert it to hex.
const std::string validChars = "/-._~%:";
bool toHex = false;
for (const char ch : input) {
if (ispunct(ch) != 0 && validChars.find(ch) == std::string::npos) {
toHex = true;
break;
}
}
if (!toHex) return input;
static constexpr char hex[] = "0123456789ABCDEF";
std::string output;
output.reserve(input.length() * 2);
for (const unsigned char ch : input) {
output.push_back(hex[ch >> 4]);
output.push_back(hex[ch & 15]);
}
return output;
}
void WVDrmFactory::printCdmMetrics(FILE* out) {
fprintf(out, "\n**** Widevine Cdm Metrics ****\n");
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
sp<wvcdm::WvContentDecryptionModule> cdm(getCDM());
std::vector<drm_metrics::WvCdmMetrics> metrics;
bool full_list_returned = true;
wvcdm::CdmResponseType result =
cdm->GetMetrics(&metrics, &full_list_returned);
if (metrics.empty()) {
fprintf(out,
"Metrics not available, please retry while streaming a video\n");
} else if (!full_list_returned) {
fprintf(out,
"Not all metrics are returned due to some GetMetric error, "
"please check logcat for possible GetMetric errors.\n");
}
if (result == wvcdm::NO_ERROR) {
for (auto& metric : metrics) {
fprintf(out, "*** Metric size=%zu\n", metric.DebugString().size());
std::string formatted;
wv_metrics::FormatWvCdmMetrics(metric, formatted);
fprintf(out, "%s\n", formatted.c_str());
}
} else {
fprintf(out, "GetMetrics failed, error=%d\n", result);
}
}
void WVDrmFactory::printCdmProperties(FILE* out) {
fprintf(out, "\n**** Widevine CDM properties ****\n");
sp<wvcdm::WvContentDecryptionModule> cdm(getCDM());
const bool isLevel1 =
cdm->IsSecurityLevelSupported(wvcdm::CdmSecurityLevel::kSecurityLevelL1);
fprintf(out, "default security level: [%s]\n", isLevel1 ? "L1" : "L3");
const std::map<std::string, std::string> cdmProperties = {
{"version- Widevine CDM:", wvcdm::QUERY_KEY_WVCDM_VERSION},
{"version- current SRM:", wvcdm::QUERY_KEY_CURRENT_SRM_VERSION},
{"version(major)- OEM Crypto API:",
wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION},
{"version(minor)- OEM Crypto API:",
wvcdm::QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION},
{"id- device:", wvcdm::QUERY_KEY_DEVICE_ID},
{"id- system:", wvcdm::QUERY_KEY_SYSTEM_ID},
{"renewal server url:", wvcdm::QUERY_KEY_RENEWAL_SERVER_URL},
{"hdcp level- max:", wvcdm::QUERY_KEY_MAX_HDCP_LEVEL},
{"hdcp level- current:", wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL},
{"num sessions- max supported:", wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS},
{"num sessions- opened:", wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS},
{"resource rating tier:", wvcdm::QUERY_KEY_RESOURCE_RATING_TIER},
{"support decrypt hash:", wvcdm::QUERY_KEY_DECRYPT_HASH_SUPPORT},
{"support SRM update:", wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT},
{"support usage table:", wvcdm::QUERY_KEY_USAGE_SUPPORT},
{"max usage table entries:", wvcdm::QUERY_KEY_MAX_USAGE_TABLE_ENTRIES},
{"OEM Crypto build info:", wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION},
{"provisioning id:", wvcdm::QUERY_KEY_PROVISIONING_ID},
{"provisioning model:", wvcdm::QUERY_KEY_PROVISIONING_MODEL},
{"analog capabilities:", wvcdm::QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES},
{"can disable analog output:",
wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT},
};
std::string value;
for (const auto& property : cdmProperties) {
cdm->QueryStatus(wvcdm::SecurityLevel::kLevelDefault, property.second,
&value);
std::string outString = stringToHex(value);
fprintf(out, "%s [%s]\n", property.first.c_str(), outString.c_str());
value.clear();
}
}
Return<void> WVDrmFactory::debug(const hidl_handle& fd,
const hidl_vec<hidl_string>& args) {
if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
ALOGE("%s: missing fd for writing", __FUNCTION__);
return Void();
}
FILE* out = fdopen(dup(fd->data[0]), "w");
fprintf(out, "\nDefault to print all info if no arguments are used.\n");
fprintf(out, "Optional arguments are:\n");
fprintf(out, "\tm:cdm metrics | p:cdm properties\n");
fprintf(out,
"Usage: adb shell lshal debug "
"android.hardware.drm@1.3::IDrmFactory/widevine [m|p]\n");
bool dumpCdmProperties, dumpCdmMetrics = false;
if (args.size() == 0) {
// default to print all info if no arguments are given
dumpCdmProperties = dumpCdmMetrics = true;
} else {
for (auto& str : args) {
fprintf(out, "args: %s\n", str.c_str());
std::string option = str.c_str();
if (option.find('m') != std::string::npos ||
option.find('M') != std::string::npos) {
dumpCdmMetrics = true;
}
if (option.find('p') != std::string::npos ||
option.find('P') != std::string::npos) {
dumpCdmProperties = true;
}
}
}
if (dumpCdmMetrics) printCdmMetrics(out);
if (dumpCdmProperties) printCdmProperties(out);
fclose(out);
return Void();
}
} // namespace widevine
} // namespace V1_3
} // namespace drm
} // namespace hardware
} // namespace wvdrm