| /* |
| * Copyright (C) 2017 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 "MockCasPlugin" |
| |
| #include <media/stagefright/foundation/hexdump.h> |
| #include <media/stagefright/MediaErrors.h> |
| #include <utils/Log.h> |
| |
| #include "MockCasPlugin.h" |
| #include "MockSessionLibrary.h" |
| |
| android::CasFactory* createCasFactory() { |
| return new android::MockCasFactory(); |
| } |
| |
| android::DescramblerFactory* createDescramblerFactory() { |
| return new android::MockDescramblerFactory(); |
| } |
| |
| namespace android { |
| |
| static const int32_t sMockId = 0xFFFF; |
| |
| bool MockCasFactory::isSystemIdSupported(int32_t CA_system_id) const { |
| return CA_system_id == sMockId; |
| } |
| |
| status_t MockCasFactory::queryPlugins( |
| std::vector<CasPluginDescriptor> *descriptors) const { |
| descriptors->clear(); |
| descriptors->push_back({sMockId, String8("MockCAS")}); |
| return OK; |
| } |
| |
| status_t MockCasFactory::createPlugin( |
| int32_t CA_system_id, |
| void* /*appData*/, |
| CasPluginCallback /*callback*/, |
| CasPlugin **plugin) { |
| if (!isSystemIdSupported(CA_system_id)) { |
| return BAD_VALUE; |
| } |
| |
| *plugin = new MockCasPlugin(); |
| return OK; |
| } |
| |
| status_t MockCasFactory::createPlugin( |
| int32_t CA_system_id, |
| void* /*appData*/, |
| CasPluginCallbackExt /*callback*/, |
| CasPlugin **plugin) { |
| if (!isSystemIdSupported(CA_system_id)) { |
| return BAD_VALUE; |
| } |
| |
| *plugin = new MockCasPlugin(); |
| return OK; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| bool MockDescramblerFactory::isSystemIdSupported(int32_t CA_system_id) const { |
| return CA_system_id == sMockId; |
| } |
| |
| status_t MockDescramblerFactory::createPlugin( |
| int32_t CA_system_id, DescramblerPlugin** plugin) { |
| if (!isSystemIdSupported(CA_system_id)) { |
| return BAD_VALUE; |
| } |
| |
| *plugin = new MockDescramblerPlugin(); |
| return OK; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| static String8 arrayToString(const std::vector<uint8_t> &array) { |
| String8 result; |
| for (size_t i = 0; i < array.size(); i++) { |
| result.appendFormat("%02x ", array[i]); |
| } |
| if (result.empty()) { |
| result.append("(null)"); |
| } |
| return result; |
| } |
| |
| MockCasPlugin::MockCasPlugin() { |
| ALOGV("CTOR"); |
| } |
| |
| MockCasPlugin::~MockCasPlugin() { |
| ALOGV("DTOR"); |
| MockSessionLibrary::get()->destroyPlugin(this); |
| } |
| |
| status_t MockCasPlugin::setStatusCallback( |
| CasPluginStatusCallback /*callback*/) { |
| ALOGV("setStatusCallback"); |
| return OK; |
| } |
| |
| status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) { |
| ALOGV("setPrivateData"); |
| return OK; |
| } |
| |
| status_t MockCasPlugin::openSession(CasSessionId* sessionId) { |
| ALOGV("openSession"); |
| return MockSessionLibrary::get()->addSession(this, sessionId); |
| } |
| |
| status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode, |
| CasSessionId* sessionId) { |
| ALOGV("openSession with intent=%d, mode=%d", intent, mode); |
| // Clear key plugin doesn't use intent and mode. |
| return MockSessionLibrary::get()->addSession(this, sessionId); |
| } |
| |
| status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) { |
| ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).c_str()); |
| Mutex::Autolock lock(mLock); |
| |
| sp<MockCasSession> session = |
| MockSessionLibrary::get()->findSession(sessionId); |
| if (session == NULL) { |
| return BAD_VALUE; |
| } |
| |
| MockSessionLibrary::get()->destroySession(sessionId); |
| return OK; |
| } |
| |
| status_t MockCasPlugin::setSessionPrivateData( |
| const CasSessionId &sessionId, const CasData& /*data*/) { |
| ALOGV("setSessionPrivateData: sessionId=%s", |
| arrayToString(sessionId).c_str()); |
| Mutex::Autolock lock(mLock); |
| |
| sp<MockCasSession> session = |
| MockSessionLibrary::get()->findSession(sessionId); |
| if (session == NULL) { |
| return BAD_VALUE; |
| } |
| return OK; |
| } |
| |
| status_t MockCasPlugin::processEcm( |
| const CasSessionId &sessionId, const CasEcm& ecm) { |
| ALOGV("processEcm: sessionId=%s", arrayToString(sessionId).c_str()); |
| Mutex::Autolock lock(mLock); |
| |
| sp<MockCasSession> session = |
| MockSessionLibrary::get()->findSession(sessionId); |
| if (session == NULL) { |
| return BAD_VALUE; |
| } |
| ALOGV("ECM: size=%zu", ecm.size()); |
| ALOGV("ECM: data=%s", arrayToString(ecm).c_str()); |
| |
| return OK; |
| } |
| |
| status_t MockCasPlugin::processEmm(const CasEmm& emm) { |
| ALOGV("processEmm"); |
| Mutex::Autolock lock(mLock); |
| |
| ALOGV("EMM: size=%zu", emm.size()); |
| ALOGV("EMM: data=%s", arrayToString(emm).c_str()); |
| |
| return OK; |
| } |
| |
| status_t MockCasPlugin::sendEvent( |
| int32_t event, int /*arg*/, const CasData& /*eventData*/) { |
| ALOGV("sendEvent: event=%d", event); |
| Mutex::Autolock lock(mLock); |
| |
| return OK; |
| } |
| |
| status_t MockCasPlugin::sendSessionEvent( |
| const CasSessionId &sessionId, int32_t event, |
| int /*arg*/, const CasData& /*eventData*/) { |
| ALOGV("sendSessionEvent: sessionId=%s, event=%d", |
| arrayToString(sessionId).c_str(), event); |
| Mutex::Autolock lock(mLock); |
| |
| return OK; |
| } |
| |
| status_t MockCasPlugin::provision(const String8 &str) { |
| ALOGV("provision: provisionString=%s", str.c_str()); |
| Mutex::Autolock lock(mLock); |
| |
| return OK; |
| } |
| |
| status_t MockCasPlugin::refreshEntitlements( |
| int32_t /*refreshType*/, const CasData &refreshData) { |
| ALOGV("refreshEntitlements: refreshData=%s", arrayToString(refreshData).c_str()); |
| Mutex::Autolock lock(mLock); |
| |
| return OK; |
| } |
| |
| ///////////////////////////////////////////////////////////////// |
| bool MockDescramblerPlugin::requiresSecureDecoderComponent( |
| const char *mime) const { |
| ALOGV("MockDescramblerPlugin::requiresSecureDecoderComponent" |
| "(mime=%s)", mime); |
| return false; |
| } |
| |
| status_t MockDescramblerPlugin::setMediaCasSession( |
| const CasSessionId &sessionId) { |
| ALOGV("MockDescramblerPlugin::setMediaCasSession"); |
| sp<MockCasSession> session = |
| MockSessionLibrary::get()->findSession(sessionId); |
| |
| if (session == NULL) { |
| ALOGE("MockDescramblerPlugin: session not found"); |
| return ERROR_DRM_SESSION_NOT_OPENED; |
| } |
| |
| return OK; |
| } |
| |
| ssize_t MockDescramblerPlugin::descramble( |
| bool secure, |
| ScramblingControl scramblingControl, |
| size_t numSubSamples, |
| const SubSample *subSamples, |
| const void *srcPtr, |
| int32_t srcOffset, |
| void *dstPtr, |
| int32_t dstOffset, |
| AString* /*errorDetailMsg*/) { |
| ALOGV("MockDescramblerPlugin::descramble(secure=%d, sctrl=%d," |
| "subSamples=%s, srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d)", |
| (int)secure, (int)scramblingControl, |
| subSamplesToString(subSamples, numSubSamples).c_str(), |
| srcPtr, dstPtr, srcOffset, dstOffset); |
| |
| return 0; |
| } |
| |
| // Conversion utilities |
| String8 MockDescramblerPlugin::arrayToString( |
| uint8_t const *array, size_t len) const |
| { |
| String8 result("{ "); |
| for (size_t i = 0; i < len; i++) { |
| result.appendFormat("0x%02x ", array[i]); |
| } |
| result += "}"; |
| return result; |
| } |
| |
| String8 MockDescramblerPlugin::subSamplesToString( |
| SubSample const *subSamples, size_t numSubSamples) const |
| { |
| String8 result; |
| for (size_t i = 0; i < numSubSamples; i++) { |
| result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i, |
| subSamples[i].mNumBytesOfClearData, |
| subSamples[i].mNumBytesOfEncryptedData); |
| } |
| return result; |
| } |
| |
| } // namespace android |
| |