diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index 6f258625..96366d35 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -238,6 +238,7 @@ LOCAL_SHARED_LIBRARIES := \ android.hidl.memory@1.0 \ libbase \ libcrypto \ + libcutils \ libdl \ libhidlbase \ libhidlmemory \ diff --git a/libwvdrmengine/include_hidl/WVDrmFactory.h b/libwvdrmengine/include_hidl/WVDrmFactory.h index f4fff3de..401c6d3b 100644 --- a/libwvdrmengine/include_hidl/WVDrmFactory.h +++ b/libwvdrmengine/include_hidl/WVDrmFactory.h @@ -17,6 +17,9 @@ namespace drm { namespace V1_3 { namespace widevine { +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_vec; + struct WVDrmFactory : public IDrmFactory { WVDrmFactory() {} virtual ~WVDrmFactory() {} @@ -40,6 +43,8 @@ struct WVDrmFactory : public IDrmFactory { Return getSupportedCryptoSchemes( getSupportedCryptoSchemes_cb _hidl_cb) override; + Return debug(const hidl_handle& fd, const hidl_vec& args); + private: WVDRM_DISALLOW_COPY_AND_ASSIGN(WVDrmFactory); @@ -48,6 +53,8 @@ struct WVDrmFactory : public IDrmFactory { static bool areSpoidsEnabled(); static bool isBlankAppPackageNameAllowed(); static int32_t firstApiLevel(); + static std::string stringToHex(const std::string& input); + static void printCdmProperties(FILE* out); friend class WVDrmFactoryTestPeer; }; diff --git a/libwvdrmengine/src_hidl/WVDrmFactory.cpp b/libwvdrmengine/src_hidl/WVDrmFactory.cpp index 1c534b59..d2e7035b 100644 --- a/libwvdrmengine/src_hidl/WVDrmFactory.cpp +++ b/libwvdrmengine/src_hidl/WVDrmFactory.cpp @@ -6,18 +6,19 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "WVCdm" +#include "WVDrmFactory.h" + #include #include -#include "WVDrmFactory.h" - -#include "android-base/properties.h" -#include "wv_cdm_constants.h" -#include "wv_content_decryption_module.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" namespace wvdrm { namespace hardware { @@ -35,25 +36,23 @@ Return WVDrmFactory::isCryptoSchemeSupported( } Return WVDrmFactory::isCryptoSchemeSupported_1_2( - const hidl_array& uuid, - const hidl_string& initDataType, - SecurityLevel level) { + const hidl_array& uuid, const hidl_string& initDataType, + SecurityLevel level) { + if (!isWidevineUUID(uuid.data()) || !isContentTypeSupported(initDataType)) { + return false; + } - 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; } - - 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 level <= SecurityLevel::SW_SECURE_DECODE; } Return WVDrmFactory::isContentTypeSupported( @@ -61,27 +60,28 @@ Return WVDrmFactory::isContentTypeSupported( return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.c_str()); } -Return WVDrmFactory::createPlugin( - const hidl_array& uuid, - const hidl_string& appPackageName, - createPlugin_cb _hidl_cb) { - +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__); + 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, " \ + 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."); + ALOGE( + "Widevine Drm HAL: Failed to create DRM Plugin, blank App Package " + "Name disallowed."); _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, plugin); return Void(); } @@ -114,15 +114,97 @@ int32_t WVDrmFactory::firstApiLevel() { return firstApiLevel; } -Return WVDrmFactory::getSupportedCryptoSchemes(getSupportedCryptoSchemes_cb _hidl_cb) { +Return WVDrmFactory::getSupportedCryptoSchemes( + getSupportedCryptoSchemes_cb _hidl_cb) { std::vector> schemes; - for (const auto &scheme : wvdrm::getSupportedCryptoSchemes()) { + 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