// // 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 #include #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" namespace wvdrm { namespace hardware { namespace drm { namespace V1_3 { namespace widevine { using wvdrm::hardware::drm::V1_2::widevine::WVDrmPlugin; WVGenericCryptoInterface WVDrmFactory::sOemCryptoInterface; Return WVDrmFactory::isCryptoSchemeSupported( const hidl_array& uuid) { return isWidevineUUID(uuid.data()); } Return WVDrmFactory::isCryptoSchemeSupported_1_2( const hidl_array& 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 WVDrmFactory::isContentTypeSupported( const hidl_string& initDataType) { return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.c_str()); } Return WVDrmFactory::createPlugin(const hidl_array& 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 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("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("ro.build.version.sdk", 0); } return firstApiLevel; } Return WVDrmFactory::getSupportedCryptoSchemes( getSupportedCryptoSchemes_cb _hidl_cb) { std::vector> 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::printCdmProperties(FILE* out) { fprintf(out, "\n**** Widevine CDM properties ****\n"); sp cdm(getCDM()); const bool isLevel1 = cdm->IsSecurityLevelSupported(wvcdm::CdmSecurityLevel::kSecurityLevelL1); fprintf(out, "current security level: [%s]\n", isLevel1 ? "L1" : "L3"); std::map 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- systen:", 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}, }; 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 WVDrmFactory::debug(const hidl_handle& fd, const hidl_vec& /*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"); printCdmProperties(out); fclose(out); return Void(); } } // namespace widevine } // namespace V1_3 } // namespace drm } // namespace hardware } // namespace wvdrm