| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // #define LOG_NDEBUG 0 |
| #define LOG_TAG "DrmMetricsLogger" |
| |
| #include <media/MediaMetrics.h> |
| #include <mediadrm/DrmHal.h> |
| #include <mediadrm/DrmMetricsLogger.h> |
| #include <mediadrm/DrmUtils.h> |
| |
| namespace android { |
| |
| namespace { |
| |
| std::vector<uint8_t> toStdVec(Vector<uint8_t> const& sessionId) { |
| auto sessionKey = sessionId.array(); |
| std::vector<uint8_t> vec(sessionKey, sessionKey + sessionId.size()); |
| return vec; |
| } |
| } // namespace |
| |
| DrmMetricsLogger::DrmMetricsLogger(IDrmFrontend frontend) |
| : mImpl(sp<DrmHal>::make()), mUuid(), mObjNonceMsb(0), mObjNonceLsb(0), mFrontend(frontend) {} |
| |
| DrmMetricsLogger::~DrmMetricsLogger() {} |
| |
| DrmStatus DrmMetricsLogger::initCheck() const { |
| DrmStatus status = mImpl->initCheck(); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::isCryptoSchemeSupported(const uint8_t uuid[16], const String8& mimeType, |
| DrmPlugin::SecurityLevel securityLevel, |
| bool* result) { |
| DrmStatus status = mImpl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::createPlugin(const uint8_t uuid[16], const String8& appPackageName) { |
| std::memcpy(mUuid, uuid, sizeof(mUuid)); |
| if (checkGetRandom(&mObjNonceMsb, __func__) == OK && |
| checkGetRandom(&mObjNonceLsb, __func__) == OK) { |
| DrmStatus status = mImpl->createPlugin(uuid, appPackageName); |
| if (status == OK) { |
| reportMediaDrmCreated(); |
| } else { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| return ERROR_DRM_RESOURCE_BUSY; |
| } |
| |
| DrmStatus DrmMetricsLogger::destroyPlugin() { |
| DrmStatus status = mImpl->destroyPlugin(); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::openSession(DrmPlugin::SecurityLevel securityLevel, |
| Vector<uint8_t>& sessionId) { |
| SessionContext ctx{}; |
| if (checkGetRandom(&ctx.mNonceMsb, __func__) == OK && |
| checkGetRandom(&ctx.mNonceLsb, __func__) == OK) { |
| DrmStatus status = mImpl->openSession(securityLevel, sessionId); |
| if (status == OK) { |
| std::vector<uint8_t> sessionKey = toStdVec(sessionId); |
| ctx.mTargetSecurityLevel = securityLevel; |
| if (getSecurityLevel(sessionId, &ctx.mActualSecurityLevel) != OK) { |
| ctx.mActualSecurityLevel = DrmPlugin::kSecurityLevelUnknown; |
| } |
| { |
| const std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| mSessionMap.insert({sessionKey, ctx}); |
| } |
| reportMediaDrmSessionOpened(sessionKey); |
| } else { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| return ERROR_DRM_RESOURCE_BUSY; |
| } |
| |
| DrmStatus DrmMetricsLogger::closeSession(Vector<uint8_t> const& sessionId) { |
| std::vector<uint8_t> sid = toStdVec(sessionId); |
| { |
| const std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| mSessionMap.erase(sid); |
| } |
| DrmStatus status = mImpl->closeSession(sessionId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, sid); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getKeyRequest(Vector<uint8_t> const& sessionId, |
| Vector<uint8_t> const& initData, String8 const& mimeType, |
| DrmPlugin::KeyType keyType, |
| KeyedVector<String8, String8> const& optionalParameters, |
| Vector<uint8_t>& request, String8& defaultUrl, |
| DrmPlugin::KeyRequestType* keyRequestType) { |
| DrmStatus status = |
| mImpl->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters, |
| request, defaultUrl, keyRequestType); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::provideKeyResponse(Vector<uint8_t> const& sessionId, |
| Vector<uint8_t> const& response, |
| Vector<uint8_t>& keySetId) { |
| DrmStatus status = mImpl->provideKeyResponse(sessionId, response, keySetId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::removeKeys(Vector<uint8_t> const& keySetId) { |
| DrmStatus status = mImpl->removeKeys(keySetId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::restoreKeys(Vector<uint8_t> const& sessionId, |
| Vector<uint8_t> const& keySetId) { |
| DrmStatus status = mImpl->restoreKeys(sessionId, keySetId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::queryKeyStatus(Vector<uint8_t> const& sessionId, |
| KeyedVector<String8, String8>& infoMap) const { |
| DrmStatus status = mImpl->queryKeyStatus(sessionId, infoMap); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getProvisionRequest(String8 const& certType, |
| String8 const& certAuthority, |
| Vector<uint8_t>& request, String8& defaultUrl) { |
| DrmStatus status = mImpl->getProvisionRequest(certType, certAuthority, request, defaultUrl); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::provideProvisionResponse(Vector<uint8_t> const& response, |
| Vector<uint8_t>& certificate, |
| Vector<uint8_t>& wrappedKey) { |
| DrmStatus status = mImpl->provideProvisionResponse(response, certificate, wrappedKey); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getSecureStops(List<Vector<uint8_t>>& secureStops) { |
| DrmStatus status = mImpl->getSecureStops(secureStops); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) { |
| DrmStatus status = mImpl->getSecureStopIds(secureStopIds); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getSecureStop(Vector<uint8_t> const& ssid, |
| Vector<uint8_t>& secureStop) { |
| DrmStatus status = mImpl->getSecureStop(ssid, secureStop); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::releaseSecureStops(Vector<uint8_t> const& ssRelease) { |
| DrmStatus status = mImpl->releaseSecureStops(ssRelease); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::removeSecureStop(Vector<uint8_t> const& ssid) { |
| DrmStatus status = mImpl->removeSecureStop(ssid); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::removeAllSecureStops() { |
| DrmStatus status = mImpl->removeAllSecureStops(); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel, |
| DrmPlugin::HdcpLevel* maxLevel) const { |
| DrmStatus status = mImpl->getHdcpLevels(connectedLevel, maxLevel); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getNumberOfSessions(uint32_t* currentSessions, |
| uint32_t* maxSessions) const { |
| DrmStatus status = mImpl->getNumberOfSessions(currentSessions, maxSessions); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getSecurityLevel(Vector<uint8_t> const& sessionId, |
| DrmPlugin::SecurityLevel* level) const { |
| DrmStatus status = mImpl->getSecurityLevel(sessionId, level); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const { |
| DrmStatus status = mImpl->getOfflineLicenseKeySetIds(keySetIds); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::removeOfflineLicense(Vector<uint8_t> const& keySetId) { |
| DrmStatus status = mImpl->removeOfflineLicense(keySetId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getOfflineLicenseState( |
| Vector<uint8_t> const& keySetId, DrmPlugin::OfflineLicenseState* licenseState) const { |
| DrmStatus status = mImpl->getOfflineLicenseState(keySetId, licenseState); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getPropertyString(String8 const& name, String8& value) const { |
| DrmStatus status = mImpl->getPropertyString(name, value); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getPropertyByteArray(String8 const& name, |
| Vector<uint8_t>& value) const { |
| DrmStatus status = mImpl->getPropertyByteArray(name, value); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setPropertyString(String8 const& name, String8 const& value) const { |
| DrmStatus status = mImpl->setPropertyString(name, value); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setPropertyByteArray(String8 const& name, |
| Vector<uint8_t> const& value) const { |
| DrmStatus status = mImpl->setPropertyByteArray(name, value); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getMetrics(const sp<IDrmMetricsConsumer>& consumer) { |
| DrmStatus status = mImpl->getMetrics(consumer); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setCipherAlgorithm(Vector<uint8_t> const& sessionId, |
| String8 const& algorithm) { |
| DrmStatus status = mImpl->setCipherAlgorithm(sessionId, algorithm); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setMacAlgorithm(Vector<uint8_t> const& sessionId, |
| String8 const& algorithm) { |
| DrmStatus status = mImpl->setMacAlgorithm(sessionId, algorithm); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId, |
| Vector<uint8_t> const& input, Vector<uint8_t> const& iv, |
| Vector<uint8_t>& output) { |
| DrmStatus status = mImpl->encrypt(sessionId, keyId, input, iv, output); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId, |
| Vector<uint8_t> const& input, Vector<uint8_t> const& iv, |
| Vector<uint8_t>& output) { |
| DrmStatus status = mImpl->decrypt(sessionId, keyId, input, iv, output); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId, |
| Vector<uint8_t> const& message, Vector<uint8_t>& signature) { |
| DrmStatus status = mImpl->sign(sessionId, keyId, message, signature); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId, |
| Vector<uint8_t> const& message, Vector<uint8_t> const& signature, |
| bool& match) { |
| DrmStatus status = mImpl->verify(sessionId, keyId, message, signature, match); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm, |
| Vector<uint8_t> const& message, |
| Vector<uint8_t> const& wrappedKey, Vector<uint8_t>& signature) { |
| DrmStatus status = mImpl->signRSA(sessionId, algorithm, message, wrappedKey, signature); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setListener(const sp<IDrmClient>& listener) { |
| DrmStatus status = mImpl->setListener(listener); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::requiresSecureDecoder(const char* mime, bool* required) const { |
| DrmStatus status = mImpl->requiresSecureDecoder(mime, required); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::requiresSecureDecoder(const char* mime, |
| DrmPlugin::SecurityLevel securityLevel, |
| bool* required) const { |
| DrmStatus status = mImpl->requiresSecureDecoder(mime, securityLevel, required); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::setPlaybackId(Vector<uint8_t> const& sessionId, |
| const char* playbackId) { |
| DrmStatus status = mImpl->setPlaybackId(sessionId, playbackId); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__, toStdVec(sessionId)); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const { |
| DrmStatus status = mImpl->getLogMessages(logs); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| DrmStatus DrmMetricsLogger::getSupportedSchemes(std::vector<uint8_t>& schemes) const { |
| DrmStatus status = mImpl->getSupportedSchemes(schemes); |
| if (status != OK) { |
| reportMediaDrmErrored(status, __func__); |
| } |
| return status; |
| } |
| |
| void DrmMetricsLogger::reportMediaDrmCreated() const { |
| mediametrics_handle_t handle(mediametrics_create("mediadrm.created")); |
| mediametrics_setInt64(handle, "uuid_msb", be64toh(mUuid[0])); |
| mediametrics_setInt64(handle, "uuid_lsb", be64toh(mUuid[1])); |
| mediametrics_setInt32(handle, "frontend", mFrontend); |
| mediametrics_selfRecord(handle); |
| mediametrics_delete(handle); |
| } |
| |
| void DrmMetricsLogger::reportMediaDrmSessionOpened(std::vector<uint8_t> sessionId) const { |
| mediametrics_handle_t handle(mediametrics_create("mediadrm.session_opened")); |
| mediametrics_setInt64(handle, "obj_nonce_msb", mObjNonceMsb); |
| mediametrics_setInt64(handle, "obj_nonce_lsb", mObjNonceLsb); |
| const std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| auto it = mSessionMap.find(sessionId); |
| if (it != mSessionMap.end()) { |
| mediametrics_setInt64(handle, "session_nonce_msb", it->second.mNonceMsb); |
| mediametrics_setInt64(handle, "session_nonce_lsb", it->second.mNonceLsb); |
| mediametrics_setInt64(handle, "target_seucrity_level", it->second.mTargetSecurityLevel); |
| mediametrics_setInt64(handle, "actual_seucrity_level", it->second.mActualSecurityLevel); |
| } |
| mediametrics_setInt32(handle, "frontend", mFrontend); |
| mediametrics_selfRecord(handle); |
| mediametrics_delete(handle); |
| } |
| |
| void DrmMetricsLogger::reportMediaDrmErrored(DrmStatus error_code, const char* api, |
| std::vector<uint8_t> sessionId) const { |
| mediametrics_handle_t handle(mediametrics_create("mediadrm.errored")); |
| mediametrics_setInt64(handle, "obj_nonce_msb", mObjNonceMsb); |
| mediametrics_setInt64(handle, "obj_nonce_lsb", mObjNonceLsb); |
| if (!sessionId.empty()) { |
| const std::lock_guard<std::mutex> lock(mSessionMapMutex); |
| auto it = mSessionMap.find(sessionId); |
| if (it != mSessionMap.end()) { |
| mediametrics_setInt64(handle, "session_nonce_msb", it->second.mNonceMsb); |
| mediametrics_setInt64(handle, "session_nonce_lsb", it->second.mNonceLsb); |
| } |
| } |
| mediametrics_setInt64(handle, "uuid_msb", be64toh(mUuid[0])); |
| mediametrics_setInt64(handle, "uuid_lsb", be64toh(mUuid[1])); |
| mediametrics_setInt32(handle, "error_code", error_code); |
| mediametrics_setCString(handle, "api", api); |
| mediametrics_setInt32(handle, "frontend", mFrontend); |
| mediametrics_selfRecord(handle); |
| mediametrics_delete(handle); |
| } |
| |
| DrmStatus DrmMetricsLogger::checkGetRandom(int64_t* nonce, const char* api) { |
| ssize_t bytes = getrandom(nonce, sizeof(int64_t), GRND_NONBLOCK); |
| if (bytes < sizeof(int64_t)) { |
| ALOGE("getrandom failed: %d", errno); |
| reportMediaDrmErrored(ERROR_DRM_RESOURCE_BUSY, api); |
| return ERROR_DRM_RESOURCE_BUSY; |
| } |
| return OK; |
| } |
| |
| } // namespace android |