1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_NDEBUG 0 18 #define LOG_TAG "MockCasPlugin" 19 20 #include <media/stagefright/foundation/hexdump.h> 21 #include <media/stagefright/MediaErrors.h> 22 #include <utils/Log.h> 23 24 #include "MockCasPlugin.h" 25 #include "MockSessionLibrary.h" 26 27 android::CasFactory* createCasFactory() { 28 return new android::MockCasFactory(); 29 } 30 31 android::DescramblerFactory* createDescramblerFactory() { 32 return new android::MockDescramblerFactory(); 33 } 34 35 namespace android { 36 37 static const int32_t sMockId = 0xFFFF; 38 39 bool MockCasFactory::isSystemIdSupported(int32_t CA_system_id) const { 40 return CA_system_id == sMockId; 41 } 42 43 status_t MockCasFactory::queryPlugins( 44 std::vector<CasPluginDescriptor> *descriptors) const { 45 descriptors->clear(); 46 descriptors->push_back({sMockId, String8("MockCAS")}); 47 return OK; 48 } 49 50 status_t MockCasFactory::createPlugin( 51 int32_t CA_system_id, 52 void* /*appData*/, 53 CasPluginCallback /*callback*/, 54 CasPlugin **plugin) { 55 if (!isSystemIdSupported(CA_system_id)) { 56 return BAD_VALUE; 57 } 58 59 *plugin = new MockCasPlugin(); 60 return OK; 61 } 62 63 status_t MockCasFactory::createPlugin( 64 int32_t CA_system_id, 65 void* /*appData*/, 66 CasPluginCallbackExt /*callback*/, 67 CasPlugin **plugin) { 68 if (!isSystemIdSupported(CA_system_id)) { 69 return BAD_VALUE; 70 } 71 72 *plugin = new MockCasPlugin(); 73 return OK; 74 } 75 76 /////////////////////////////////////////////////////////////////////////////// 77 78 bool MockDescramblerFactory::isSystemIdSupported(int32_t CA_system_id) const { 79 return CA_system_id == sMockId; 80 } 81 82 status_t MockDescramblerFactory::createPlugin( 83 int32_t CA_system_id, DescramblerPlugin** plugin) { 84 if (!isSystemIdSupported(CA_system_id)) { 85 return BAD_VALUE; 86 } 87 88 *plugin = new MockDescramblerPlugin(); 89 return OK; 90 } 91 92 /////////////////////////////////////////////////////////////////////////////// 93 94 static String8 arrayToString(const std::vector<uint8_t> &array) { 95 String8 result; 96 for (size_t i = 0; i < array.size(); i++) { 97 result.appendFormat("%02x ", array[i]); 98 } 99 if (result.isEmpty()) { 100 result.append("(null)"); 101 } 102 return result; 103 } 104 105 MockCasPlugin::MockCasPlugin() { 106 ALOGV("CTOR"); 107 } 108 109 MockCasPlugin::~MockCasPlugin() { 110 ALOGV("DTOR"); 111 MockSessionLibrary::get()->destroyPlugin(this); 112 } 113 114 status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) { 115 ALOGV("setPrivateData"); 116 return OK; 117 } 118 119 status_t MockCasPlugin::openSession(CasSessionId* sessionId) { 120 ALOGV("openSession"); 121 return MockSessionLibrary::get()->addSession(this, sessionId); 122 } 123 124 status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) { 125 ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string()); 126 Mutex::Autolock lock(mLock); 127 128 sp<MockCasSession> session = 129 MockSessionLibrary::get()->findSession(sessionId); 130 if (session == NULL) { 131 return BAD_VALUE; 132 } 133 134 MockSessionLibrary::get()->destroySession(sessionId); 135 return OK; 136 } 137 138 status_t MockCasPlugin::setSessionPrivateData( 139 const CasSessionId &sessionId, const CasData& /*data*/) { 140 ALOGV("setSessionPrivateData: sessionId=%s", 141 arrayToString(sessionId).string()); 142 Mutex::Autolock lock(mLock); 143 144 sp<MockCasSession> session = 145 MockSessionLibrary::get()->findSession(sessionId); 146 if (session == NULL) { 147 return BAD_VALUE; 148 } 149 return OK; 150 } 151 152 status_t MockCasPlugin::processEcm( 153 const CasSessionId &sessionId, const CasEcm& ecm) { 154 ALOGV("processEcm: sessionId=%s", arrayToString(sessionId).string()); 155 Mutex::Autolock lock(mLock); 156 157 sp<MockCasSession> session = 158 MockSessionLibrary::get()->findSession(sessionId); 159 if (session == NULL) { 160 return BAD_VALUE; 161 } 162 ALOGV("ECM: size=%zu", ecm.size()); 163 ALOGV("ECM: data=%s", arrayToString(ecm).string()); 164 165 return OK; 166 } 167 168 status_t MockCasPlugin::processEmm(const CasEmm& emm) { 169 ALOGV("processEmm"); 170 Mutex::Autolock lock(mLock); 171 172 ALOGV("EMM: size=%zu", emm.size()); 173 ALOGV("EMM: data=%s", arrayToString(emm).string()); 174 175 return OK; 176 } 177 178 status_t MockCasPlugin::sendEvent( 179 int32_t event, int /*arg*/, const CasData& /*eventData*/) { 180 ALOGV("sendEvent: event=%d", event); 181 Mutex::Autolock lock(mLock); 182 183 return OK; 184 } 185 186 status_t MockCasPlugin::sendSessionEvent( 187 const CasSessionId &sessionId, int32_t event, 188 int /*arg*/, const CasData& /*eventData*/) { 189 ALOGV("sendSessionEvent: sessionId=%s, event=%d", 190 arrayToString(sessionId).string(), event); 191 Mutex::Autolock lock(mLock); 192 193 return OK; 194 } 195 196 status_t MockCasPlugin::provision(const String8 &str) { 197 ALOGV("provision: provisionString=%s", str.string()); 198 Mutex::Autolock lock(mLock); 199 200 return OK; 201 } 202 203 status_t MockCasPlugin::refreshEntitlements( 204 int32_t /*refreshType*/, const CasData &refreshData) { 205 ALOGV("refreshEntitlements: refreshData=%s", arrayToString(refreshData).string()); 206 Mutex::Autolock lock(mLock); 207 208 return OK; 209 } 210 211 ///////////////////////////////////////////////////////////////// 212 bool MockDescramblerPlugin::requiresSecureDecoderComponent( 213 const char *mime) const { 214 ALOGV("MockDescramblerPlugin::requiresSecureDecoderComponent" 215 "(mime=%s)", mime); 216 return false; 217 } 218 219 status_t MockDescramblerPlugin::setMediaCasSession( 220 const CasSessionId &sessionId) { 221 ALOGV("MockDescramblerPlugin::setMediaCasSession"); 222 sp<MockCasSession> session = 223 MockSessionLibrary::get()->findSession(sessionId); 224 225 if (session == NULL) { 226 ALOGE("MockDescramblerPlugin: session not found"); 227 return ERROR_DRM_SESSION_NOT_OPENED; 228 } 229 230 return OK; 231 } 232 233 ssize_t MockDescramblerPlugin::descramble( 234 bool secure, 235 ScramblingControl scramblingControl, 236 size_t numSubSamples, 237 const SubSample *subSamples, 238 const void *srcPtr, 239 int32_t srcOffset, 240 void *dstPtr, 241 int32_t dstOffset, 242 AString* /*errorDetailMsg*/) { 243 ALOGV("MockDescramblerPlugin::descramble(secure=%d, sctrl=%d," 244 "subSamples=%s, srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d)", 245 (int)secure, (int)scramblingControl, 246 subSamplesToString(subSamples, numSubSamples).string(), 247 srcPtr, dstPtr, srcOffset, dstOffset); 248 249 return 0; 250 } 251 252 // Conversion utilities 253 String8 MockDescramblerPlugin::arrayToString( 254 uint8_t const *array, size_t len) const 255 { 256 String8 result("{ "); 257 for (size_t i = 0; i < len; i++) { 258 result.appendFormat("0x%02x ", array[i]); 259 } 260 result += "}"; 261 return result; 262 } 263 264 String8 MockDescramblerPlugin::subSamplesToString( 265 SubSample const *subSamples, size_t numSubSamples) const 266 { 267 String8 result; 268 for (size_t i = 0; i < numSubSamples; i++) { 269 result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i, 270 subSamples[i].mNumBytesOfClearData, 271 subSamples[i].mNumBytesOfEncryptedData); 272 } 273 return result; 274 } 275 276 } // namespace android 277 278