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 
setStatusCallback(CasPluginStatusCallback)114 status_t MockCasPlugin::setStatusCallback(
115     CasPluginStatusCallback /*callback*/) {
116     ALOGV("setStatusCallback");
117     return OK;
118 }
119 
setPrivateData(const CasData &)120 status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
121     ALOGV("setPrivateData");
122     return OK;
123 }
124 
openSession(CasSessionId * sessionId)125 status_t MockCasPlugin::openSession(CasSessionId* sessionId) {
126     ALOGV("openSession");
127     return MockSessionLibrary::get()->addSession(this, sessionId);
128 }
129 
openSession(uint32_t intent,uint32_t mode,CasSessionId * sessionId)130 status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode,
131     CasSessionId* sessionId) {
132     ALOGV("openSession with intent=%d, mode=%d", intent, mode);
133     // Clear key plugin doesn't use intent and mode.
134     return MockSessionLibrary::get()->addSession(this, sessionId);
135 }
136 
closeSession(const CasSessionId & sessionId)137 status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
138     ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string());
139     Mutex::Autolock lock(mLock);
140 
141     sp<MockCasSession> session =
142             MockSessionLibrary::get()->findSession(sessionId);
143     if (session == NULL) {
144         return BAD_VALUE;
145     }
146 
147     MockSessionLibrary::get()->destroySession(sessionId);
148     return OK;
149 }
150 
setSessionPrivateData(const CasSessionId & sessionId,const CasData &)151 status_t MockCasPlugin::setSessionPrivateData(
152         const CasSessionId &sessionId, const CasData& /*data*/) {
153     ALOGV("setSessionPrivateData: sessionId=%s",
154             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     return OK;
163 }
164 
processEcm(const CasSessionId & sessionId,const CasEcm & ecm)165 status_t MockCasPlugin::processEcm(
166         const CasSessionId &sessionId, const CasEcm& ecm) {
167     ALOGV("processEcm: sessionId=%s", arrayToString(sessionId).string());
168     Mutex::Autolock lock(mLock);
169 
170     sp<MockCasSession> session =
171             MockSessionLibrary::get()->findSession(sessionId);
172     if (session == NULL) {
173         return BAD_VALUE;
174     }
175     ALOGV("ECM: size=%zu", ecm.size());
176     ALOGV("ECM: data=%s", arrayToString(ecm).string());
177 
178     return OK;
179 }
180 
processEmm(const CasEmm & emm)181 status_t MockCasPlugin::processEmm(const CasEmm& emm) {
182     ALOGV("processEmm");
183     Mutex::Autolock lock(mLock);
184 
185     ALOGV("EMM: size=%zu", emm.size());
186     ALOGV("EMM: data=%s", arrayToString(emm).string());
187 
188     return OK;
189 }
190 
sendEvent(int32_t event,int,const CasData &)191 status_t MockCasPlugin::sendEvent(
192         int32_t event, int /*arg*/, const CasData& /*eventData*/) {
193     ALOGV("sendEvent: event=%d", event);
194     Mutex::Autolock lock(mLock);
195 
196     return OK;
197 }
198 
sendSessionEvent(const CasSessionId & sessionId,int32_t event,int,const CasData &)199 status_t MockCasPlugin::sendSessionEvent(
200         const CasSessionId &sessionId, int32_t event,
201         int /*arg*/, const CasData& /*eventData*/) {
202     ALOGV("sendSessionEvent: sessionId=%s, event=%d",
203           arrayToString(sessionId).string(), event);
204     Mutex::Autolock lock(mLock);
205 
206     return OK;
207 }
208 
provision(const String8 & str)209 status_t MockCasPlugin::provision(const String8 &str) {
210     ALOGV("provision: provisionString=%s", str.string());
211     Mutex::Autolock lock(mLock);
212 
213     return OK;
214 }
215 
refreshEntitlements(int32_t,const CasData & refreshData)216 status_t MockCasPlugin::refreshEntitlements(
217         int32_t /*refreshType*/, const CasData &refreshData) {
218     ALOGV("refreshEntitlements: refreshData=%s", arrayToString(refreshData).string());
219     Mutex::Autolock lock(mLock);
220 
221     return OK;
222 }
223 
224 /////////////////////////////////////////////////////////////////
requiresSecureDecoderComponent(const char * mime) const225 bool MockDescramblerPlugin::requiresSecureDecoderComponent(
226         const char *mime) const {
227     ALOGV("MockDescramblerPlugin::requiresSecureDecoderComponent"
228             "(mime=%s)", mime);
229     return false;
230 }
231 
setMediaCasSession(const CasSessionId & sessionId)232 status_t MockDescramblerPlugin::setMediaCasSession(
233         const CasSessionId &sessionId) {
234     ALOGV("MockDescramblerPlugin::setMediaCasSession");
235     sp<MockCasSession> session =
236             MockSessionLibrary::get()->findSession(sessionId);
237 
238     if (session == NULL) {
239         ALOGE("MockDescramblerPlugin: session not found");
240         return ERROR_DRM_SESSION_NOT_OPENED;
241     }
242 
243     return OK;
244 }
245 
descramble(bool secure,ScramblingControl scramblingControl,size_t numSubSamples,const SubSample * subSamples,const void * srcPtr,int32_t srcOffset,void * dstPtr,int32_t dstOffset,AString *)246 ssize_t MockDescramblerPlugin::descramble(
247         bool secure,
248         ScramblingControl scramblingControl,
249         size_t numSubSamples,
250         const SubSample *subSamples,
251         const void *srcPtr,
252         int32_t srcOffset,
253         void *dstPtr,
254         int32_t dstOffset,
255         AString* /*errorDetailMsg*/) {
256     ALOGV("MockDescramblerPlugin::descramble(secure=%d, sctrl=%d,"
257           "subSamples=%s, srcPtr=%p, dstPtr=%p, srcOffset=%d, dstOffset=%d)",
258           (int)secure, (int)scramblingControl,
259           subSamplesToString(subSamples, numSubSamples).string(),
260           srcPtr, dstPtr, srcOffset, dstOffset);
261 
262     return 0;
263 }
264 
265 // Conversion utilities
arrayToString(uint8_t const * array,size_t len) const266 String8 MockDescramblerPlugin::arrayToString(
267         uint8_t const *array, size_t len) const
268 {
269     String8 result("{ ");
270     for (size_t i = 0; i < len; i++) {
271         result.appendFormat("0x%02x ", array[i]);
272     }
273     result += "}";
274     return result;
275 }
276 
subSamplesToString(SubSample const * subSamples,size_t numSubSamples) const277 String8 MockDescramblerPlugin::subSamplesToString(
278         SubSample const *subSamples, size_t numSubSamples) const
279 {
280     String8 result;
281     for (size_t i = 0; i < numSubSamples; i++) {
282         result.appendFormat("[%zu] {clear:%u, encrypted:%u} ", i,
283                             subSamples[i].mNumBytesOfClearData,
284                             subSamples[i].mNumBytesOfEncryptedData);
285     }
286     return result;
287 }
288 
289 } // namespace android
290 
291