MockDrmCryptoPlugin.cpp revision 441a78d5e224e0d67f9b52fa9adc795c6944159b
1/*
2 * Copyright (C) 2013 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 "MockDrmCryptoPlugin"
19#include <utils/Log.h>
20
21
22#include "drm/DrmAPI.h"
23#include "MockDrmCryptoPlugin.h"
24
25using namespace android;
26
27// Shared library entry point
28DrmFactory *createDrmFactory()
29{
30    return new MockDrmFactory();
31}
32
33// Shared library entry point
34CryptoFactory *createCryptoFactory()
35{
36    return new MockCryptoFactory();
37}
38
39const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
40                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
41
42namespace android {
43
44    // MockDrmFactory
45    bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16])
46    {
47        return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
48    }
49
50    status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin)
51    {
52        *plugin = new MockDrmPlugin();
53        return OK;
54    }
55
56    // MockCryptoFactory
57    bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const
58    {
59        return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
60    }
61
62    status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data,
63                                             size_t size, CryptoPlugin **plugin)
64    {
65        *plugin = new MockCryptoPlugin();
66        return OK;
67    }
68
69
70    // MockDrmPlugin methods
71
72    status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId)
73    {
74        const size_t kSessionIdSize = 8;
75
76        Mutex::Autolock lock(mLock);
77        for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) {
78            long r = random();
79            sessionId.appendArray((uint8_t *)&r, sizeof(long));
80        }
81        mSessions.add(sessionId);
82
83        ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string());
84        return OK;
85    }
86
87    status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
88    {
89        Mutex::Autolock lock(mLock);
90        ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string());
91        ssize_t index = findSession(sessionId);
92        if (index == kNotFound) {
93            ALOGD("Invalid sessionId");
94            return BAD_VALUE;
95        }
96        mSessions.removeAt(index);
97        return OK;
98    }
99
100
101    status_t MockDrmPlugin::getLicenseRequest(Vector<uint8_t> const &sessionId,
102                                              Vector<uint8_t> const &initData,
103                                              String8 const &mimeType, LicenseType licenseType,
104                                              KeyedVector<String8, String8> const &optionalParameters,
105                                              Vector<uint8_t> &request, String8 &defaultUrl)
106    {
107        Mutex::Autolock lock(mLock);
108        ALOGD("MockDrmPlugin::getLicenseRequest(sessionId=%s, initData=%s, mimeType=%s"
109              ", licenseType=%d, optionalParameters=%s))",
110              vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(),
111              licenseType, stringMapToString(optionalParameters).string());
112
113        ssize_t index = findSession(sessionId);
114        if (index == kNotFound) {
115            ALOGD("Invalid sessionId");
116            return BAD_VALUE;
117        }
118
119        // Properties used in mock test, set by mock plugin and verifed cts test app
120        //   byte[] initData           -> mock-initdata
121        //   string mimeType           -> mock-mimetype
122        //   string licenseType        -> mock-licensetype
123        //   string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2}
124
125        mByteArrayProperties.add(String8("mock-initdata"), initData);
126        mStringProperties.add(String8("mock-mimetype"), mimeType);
127
128        String8 licenseTypeStr;
129        licenseTypeStr.appendFormat("%d", (int)licenseType);
130        mStringProperties.add(String8("mock-licensetype"), licenseTypeStr);
131
132        String8 params;
133        for (size_t i = 0; i < optionalParameters.size(); i++) {
134            params.appendFormat("%s{%s,%s}", i ? "," : "",
135                                optionalParameters.keyAt(i).string(),
136                                optionalParameters.valueAt(i).string());
137        }
138        mStringProperties.add(String8("mock-optparams"), params);
139
140        // Properties used in mock test, set by cts test app returned from mock plugin
141        //   byte[] mock-request       -> request
142        //   string mock-default-url   -> defaultUrl
143
144        index = mByteArrayProperties.indexOfKey(String8("mock-request"));
145        if (index < 0) {
146            ALOGD("Missing 'mock-request' parameter for mock");
147            return BAD_VALUE;
148        } else {
149            request = mByteArrayProperties.valueAt(index);
150        }
151
152        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
153        if (index < 0) {
154            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
155            return BAD_VALUE;
156        } else {
157            defaultUrl = mStringProperties.valueAt(index);
158        }
159        return OK;
160    }
161
162    status_t MockDrmPlugin::provideLicenseResponse(Vector<uint8_t> const &sessionId,
163                                                   Vector<uint8_t> const &response)
164    {
165        Mutex::Autolock lock(mLock);
166        ALOGD("MockDrmPlugin::provideLicenseResponse(sessionId=%s, response=%s)",
167              vectorToString(sessionId).string(), vectorToString(response).string());
168        ssize_t index = findSession(sessionId);
169        if (index == kNotFound) {
170            ALOGD("Invalid sessionId");
171            return BAD_VALUE;
172        }
173        if (response.size() == 0) {
174            return BAD_VALUE;
175        }
176
177        // Properties used in mock test, set by mock plugin and verifed cts test app
178        //   byte[] response            -> mock-response
179
180        mByteArrayProperties.add(String8("mock-response"), response);
181
182        return OK;
183    }
184
185    status_t MockDrmPlugin::removeLicense(Vector<uint8_t> const &sessionId)
186    {
187        Mutex::Autolock lock(mLock);
188        ALOGD("MockDrmPlugin::removeLicense(sessionId=%s)",
189              vectorToString(sessionId).string());
190        ssize_t index = findSession(sessionId);
191        if (index == kNotFound) {
192            ALOGD("Invalid sessionId");
193            return BAD_VALUE;
194        }
195
196        return OK;
197    }
198
199    status_t MockDrmPlugin::queryLicenseStatus(Vector<uint8_t> const &sessionId,
200                                               KeyedVector<String8, String8> &infoMap) const
201    {
202        ALOGD("MockDrmPlugin::queryLicenseStatus(sessionId=%s)",
203              vectorToString(sessionId).string());
204
205        ssize_t index = findSession(sessionId);
206        if (index == kNotFound) {
207            ALOGD("Invalid sessionId");
208            return BAD_VALUE;
209        }
210
211        infoMap.add(String8("purchaseDuration"), String8("1000"));
212        infoMap.add(String8("licenseDuration"), String8("100"));
213        return OK;
214    }
215
216    status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request,
217                                                String8 &defaultUrl)
218    {
219        Mutex::Autolock lock(mLock);
220        ALOGD("MockDrmPlugin::getProvisionRequest()");
221
222        // Properties used in mock test, set by cts test app returned from mock plugin
223        //   byte[] mock-request       -> request
224        //   string mock-default-url   -> defaultUrl
225
226        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request"));
227        if (index < 0) {
228            ALOGD("Missing 'mock-request' parameter for mock");
229            return BAD_VALUE;
230        } else {
231            request = mByteArrayProperties.valueAt(index);
232        }
233
234        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
235        if (index < 0) {
236            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
237            return BAD_VALUE;
238        } else {
239            defaultUrl = mStringProperties.valueAt(index);
240        }
241        return OK;
242    }
243
244    status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response)
245    {
246        Mutex::Autolock lock(mLock);
247        ALOGD("MockDrmPlugin::provideProvisionResponse(%s)",
248              vectorToString(response).string());
249
250        // Properties used in mock test, set by mock plugin and verifed cts test app
251        //   byte[] response            -> mock-response
252
253        mByteArrayProperties.add(String8("mock-response"), response);
254        return OK;
255    }
256
257    status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
258    {
259        Mutex::Autolock lock(mLock);
260        ALOGD("MockDrmPlugin::getSecureStops()");
261        const uint8_t ss1[] = {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89};
262        const uint8_t ss2[] = {0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99};
263
264        Vector<uint8_t> vec;
265        vec.appendArray(ss1, sizeof(ss1));
266        secureStops.push_back(vec);
267
268        vec.clear();
269        vec.appendArray(ss2, sizeof(ss2));
270        secureStops.push_back(vec);
271        return OK;
272    }
273
274    status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
275    {
276        Mutex::Autolock lock(mLock);
277        ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
278              vectorToString(ssRelease).string());
279        return OK;
280    }
281
282    status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
283    {
284        ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
285        ssize_t index = mStringProperties.indexOfKey(name);
286        if (index < 0) {
287            ALOGD("no property for '%s'", name.string());
288            return BAD_VALUE;
289        }
290        value = mStringProperties.valueAt(index);
291        return OK;
292    }
293
294    status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
295                                                 Vector<uint8_t> &value) const
296    {
297        ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
298        ssize_t index = mByteArrayProperties.indexOfKey(name);
299        if (index < 0) {
300            ALOGD("no property for '%s'", name.string());
301            return BAD_VALUE;
302        }
303        value = mByteArrayProperties.valueAt(index);
304        return OK;
305    }
306
307    status_t MockDrmPlugin::setPropertyString(String8 const &name,
308                                              String8 const &value)
309    {
310        Mutex::Autolock lock(mLock);
311        ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
312              name.string(), value.string());
313        mStringProperties.add(name, value);
314        return OK;
315    }
316
317    status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
318                                                 Vector<uint8_t> const &value)
319    {
320        Mutex::Autolock lock(mLock);
321        ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
322              name.string(), vectorToString(value).string());
323        mByteArrayProperties.add(name, value);
324        return OK;
325    }
326
327    ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
328    {
329        ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
330        for (size_t i = 0; i < mSessions.size(); ++i) {
331            if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
332                return i;
333            }
334        }
335        return kNotFound;
336    }
337
338    // Conversion utilities
339    String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
340    {
341        return arrayToString(vector.array(), vector.size());
342    }
343
344    String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
345    {
346        String8 result("{ ");
347        for (size_t i = 0; i < len; i++) {
348            result.appendFormat("0x%02x ", array[i]);
349        }
350        result += "}";
351        return result;
352    }
353
354    String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
355    {
356        String8 result("{ ");
357        for (size_t i = 0; i < map.size(); i++) {
358            result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
359                                map.keyAt(i).string(), map.valueAt(i).string());
360        }
361        return result + " }";
362    }
363
364    bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
365        return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
366    }
367
368    //
369    // Crypto Plugin
370    //
371
372    bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
373    {
374        ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
375        return false;
376    }
377
378    ssize_t
379    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
380                              Mode mode, const void *srcPtr, const SubSample *subSamples,
381                              size_t numSubSamples, void *dstPtr, AString *errorDetailMsg)
382    {
383        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
384              "subSamples=%s, dst=%p)",
385              (int)secure,
386              arrayToString(key, sizeof(key)).string(),
387              arrayToString(iv, sizeof(iv)).string(),
388              (int)mode, srcPtr,
389              subSamplesToString(subSamples, numSubSamples).string(),
390              dstPtr);
391        return OK;
392    }
393
394    // Conversion utilities
395    String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
396    {
397        String8 result("{ ");
398        for (size_t i = 0; i < len; i++) {
399            result.appendFormat("0x%02x ", array[i]);
400        }
401        result += "}";
402        return result;
403    }
404
405    String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
406                                                 size_t numSubSamples) const
407    {
408        String8 result;
409        for (size_t i = 0; i < numSubSamples; i++) {
410            result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i,
411                                subSamples[i].mNumBytesOfClearData,
412                                subSamples[i].mNumBytesOfEncryptedData);
413        }
414        return result;
415    }
416
417};
418