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
createCasFactory()27 android::CasFactory* createCasFactory() {
28 return new android::MockCasFactory();
29 }
30
createDescramblerFactory()31 android::DescramblerFactory* createDescramblerFactory() {
32 return new android::MockDescramblerFactory();
33 }
34
35 namespace android {
36
37 static const int32_t sMockId = 0xFFFF;
38
isSystemIdSupported(int32_t CA_system_id) const39 bool MockCasFactory::isSystemIdSupported(int32_t CA_system_id) const {
40 return CA_system_id == sMockId;
41 }
42
queryPlugins(std::vector<CasPluginDescriptor> * descriptors) const43 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
createPlugin(int32_t CA_system_id,void *,CasPluginCallback,CasPlugin ** plugin)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
createPlugin(int32_t CA_system_id,void *,CasPluginCallbackExt,CasPlugin ** plugin)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
isSystemIdSupported(int32_t CA_system_id) const78 bool MockDescramblerFactory::isSystemIdSupported(int32_t CA_system_id) const {
79 return CA_system_id == sMockId;
80 }
81
createPlugin(int32_t CA_system_id,DescramblerPlugin ** plugin)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
arrayToString(const std::vector<uint8_t> & array)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
MockCasPlugin()105 MockCasPlugin::MockCasPlugin() {
106 ALOGV("CTOR");
107 }
108
~MockCasPlugin()109 MockCasPlugin::~MockCasPlugin() {
110 ALOGV("DTOR");
111 MockSessionLibrary::get()->destroyPlugin(this);
112 }
113
setPrivateData(const CasData &)114 status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
115 ALOGV("setPrivateData");
116 return OK;
117 }
118
openSession(CasSessionId * sessionId)119 status_t MockCasPlugin::openSession(CasSessionId* sessionId) {
120 ALOGV("openSession");
121 return MockSessionLibrary::get()->addSession(this, sessionId);
122 }
123
closeSession(const CasSessionId & sessionId)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
setSessionPrivateData(const CasSessionId & sessionId,const CasData &)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
processEcm(const CasSessionId & sessionId,const CasEcm & ecm)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
processEmm(const CasEmm & emm)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
sendEvent(int32_t event,int,const CasData &)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
sendSessionEvent(const CasSessionId & sessionId,int32_t event,int,const CasData &)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
provision(const String8 & str)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
refreshEntitlements(int32_t,const CasData & refreshData)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 /////////////////////////////////////////////////////////////////
requiresSecureDecoderComponent(const char * mime) const212 bool MockDescramblerPlugin::requiresSecureDecoderComponent(
213 const char *mime) const {
214 ALOGV("MockDescramblerPlugin::requiresSecureDecoderComponent"
215 "(mime=%s)", mime);
216 return false;
217 }
218
setMediaCasSession(const CasSessionId & sessionId)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
descramble(bool secure,ScramblingControl scramblingControl,size_t numSubSamples,const SubSample * subSamples,const void * srcPtr,int32_t srcOffset,void * dstPtr,int32_t dstOffset,AString *)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
arrayToString(uint8_t const * array,size_t len) const253 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
subSamplesToString(SubSample const * subSamples,size_t numSubSamples) const264 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