MockDrmCryptoPlugin.cpp revision c0d5f1f8405de861ed6f1725f26cd6601e7103ab
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#include "media/stagefright/MediaErrors.h"
25
26using namespace android;
27
28// Shared library entry point
29DrmFactory *createDrmFactory()
30{
31    return new MockDrmFactory();
32}
33
34// Shared library entry point
35CryptoFactory *createCryptoFactory()
36{
37    return new MockCryptoFactory();
38}
39
40const uint8_t mock_uuid[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
41                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
42
43namespace android {
44
45    // MockDrmFactory
46    bool MockDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16])
47    {
48        return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
49    }
50
51    status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin)
52    {
53        *plugin = new MockDrmPlugin();
54        return OK;
55    }
56
57    // MockCryptoFactory
58    bool MockCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const
59    {
60        return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
61    }
62
63    status_t MockCryptoFactory::createPlugin(const uint8_t uuid[16], const void *data,
64                                             size_t size, CryptoPlugin **plugin)
65    {
66        *plugin = new MockCryptoPlugin();
67        return OK;
68    }
69
70
71    // MockDrmPlugin methods
72
73    status_t MockDrmPlugin::openSession(Vector<uint8_t> &sessionId)
74    {
75        const size_t kSessionIdSize = 8;
76
77        Mutex::Autolock lock(mLock);
78        for (size_t i = 0; i < kSessionIdSize / sizeof(long); i++) {
79            long r = random();
80            sessionId.appendArray((uint8_t *)&r, sizeof(long));
81        }
82        mSessions.add(sessionId);
83
84        ALOGD("MockDrmPlugin::openSession() -> %s", vectorToString(sessionId).string());
85        return OK;
86    }
87
88    status_t MockDrmPlugin::closeSession(Vector<uint8_t> const &sessionId)
89    {
90        Mutex::Autolock lock(mLock);
91        ALOGD("MockDrmPlugin::closeSession(%s)", vectorToString(sessionId).string());
92        ssize_t index = findSession(sessionId);
93        if (index == kNotFound) {
94            ALOGD("Invalid sessionId");
95            return BAD_VALUE;
96        }
97        mSessions.removeAt(index);
98        return OK;
99    }
100
101
102    status_t MockDrmPlugin::getKeyRequest(Vector<uint8_t> const &sessionId,
103                                          Vector<uint8_t> const &initData,
104                                          String8 const &mimeType, KeyType keyType,
105                                          KeyedVector<String8, String8> const &optionalParameters,
106                                          Vector<uint8_t> &request, String8 &defaultUrl)
107    {
108        Mutex::Autolock lock(mLock);
109        ALOGD("MockDrmPlugin::getKeyRequest(sessionId=%s, initData=%s, mimeType=%s"
110              ", keyType=%d, optionalParameters=%s))",
111              vectorToString(sessionId).string(), vectorToString(initData).string(), mimeType.string(),
112              keyType, stringMapToString(optionalParameters).string());
113
114        ssize_t index = findSession(sessionId);
115        if (index == kNotFound) {
116            ALOGD("Invalid sessionId");
117            return BAD_VALUE;
118        }
119
120        // Properties used in mock test, set by mock plugin and verifed cts test app
121        //   byte[] initData           -> mock-initdata
122        //   string mimeType           -> mock-mimetype
123        //   string keyType            -> mock-keytype
124        //   string optionalParameters -> mock-optparams formatted as {key1,value1},{key2,value2}
125
126        mByteArrayProperties.add(String8("mock-initdata"), initData);
127        mStringProperties.add(String8("mock-mimetype"), mimeType);
128
129        String8 keyTypeStr;
130        keyTypeStr.appendFormat("%d", (int)keyType);
131        mStringProperties.add(String8("mock-keytype"), keyTypeStr);
132
133        String8 params;
134        for (size_t i = 0; i < optionalParameters.size(); i++) {
135            params.appendFormat("%s{%s,%s}", i ? "," : "",
136                                optionalParameters.keyAt(i).string(),
137                                optionalParameters.valueAt(i).string());
138        }
139        mStringProperties.add(String8("mock-optparams"), params);
140
141        // Properties used in mock test, set by cts test app returned from mock plugin
142        //   byte[] mock-request       -> request
143        //   string mock-default-url   -> defaultUrl
144
145        index = mByteArrayProperties.indexOfKey(String8("mock-request"));
146        if (index < 0) {
147            ALOGD("Missing 'mock-request' parameter for mock");
148            return BAD_VALUE;
149        } else {
150            request = mByteArrayProperties.valueAt(index);
151        }
152
153        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
154        if (index < 0) {
155            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
156            return BAD_VALUE;
157        } else {
158            defaultUrl = mStringProperties.valueAt(index);
159        }
160        return OK;
161    }
162
163    status_t MockDrmPlugin::provideKeyResponse(Vector<uint8_t> const &sessionId,
164                                               Vector<uint8_t> const &response,
165                                               Vector<uint8_t> &keySetId)
166    {
167        Mutex::Autolock lock(mLock);
168        ALOGD("MockDrmPlugin::provideKeyResponse(sessionId=%s, response=%s)",
169              vectorToString(sessionId).string(), vectorToString(response).string());
170        ssize_t index = findSession(sessionId);
171        if (index == kNotFound) {
172            ALOGD("Invalid sessionId");
173            return BAD_VALUE;
174        }
175        if (response.size() == 0) {
176            return BAD_VALUE;
177        }
178
179        // Properties used in mock test, set by mock plugin and verifed cts test app
180        //   byte[] response            -> mock-response
181        mByteArrayProperties.add(String8("mock-response"), response);
182
183        const size_t kKeySetIdSize = 8;
184
185        for (size_t i = 0; i < kKeySetIdSize / sizeof(long); i++) {
186            long r = random();
187            keySetId.appendArray((uint8_t *)&r, sizeof(long));
188        }
189        mKeySets.add(keySetId);
190
191        return OK;
192    }
193
194    status_t MockDrmPlugin::removeKeys(Vector<uint8_t> const &keySetId)
195    {
196        Mutex::Autolock lock(mLock);
197        ALOGD("MockDrmPlugin::removeKeys(keySetId=%s)",
198              vectorToString(keySetId).string());
199
200        ssize_t index = findKeySet(keySetId);
201        if (index == kNotFound) {
202            ALOGD("Invalid keySetId");
203            return BAD_VALUE;
204        }
205        mKeySets.removeAt(index);
206
207        return OK;
208    }
209
210    status_t MockDrmPlugin::restoreKeys(Vector<uint8_t> const &sessionId,
211                                        Vector<uint8_t> const &keySetId)
212    {
213        Mutex::Autolock lock(mLock);
214        ALOGD("MockDrmPlugin::restoreKeys(sessionId=%s, keySetId=%s)",
215              vectorToString(sessionId).string(),
216              vectorToString(keySetId).string());
217        ssize_t index = findSession(sessionId);
218        if (index == kNotFound) {
219            ALOGD("Invalid sessionId");
220            return BAD_VALUE;
221        }
222
223        index = findKeySet(keySetId);
224        if (index == kNotFound) {
225            ALOGD("Invalid keySetId");
226            return BAD_VALUE;
227        }
228
229        return OK;
230    }
231
232    status_t MockDrmPlugin::queryKeyStatus(Vector<uint8_t> const &sessionId,
233                                               KeyedVector<String8, String8> &infoMap) const
234    {
235        ALOGD("MockDrmPlugin::queryKeyStatus(sessionId=%s)",
236              vectorToString(sessionId).string());
237
238        ssize_t index = findSession(sessionId);
239        if (index == kNotFound) {
240            ALOGD("Invalid sessionId");
241            return BAD_VALUE;
242        }
243
244        infoMap.add(String8("purchaseDuration"), String8("1000"));
245        infoMap.add(String8("licenseDuration"), String8("100"));
246        return OK;
247    }
248
249    status_t MockDrmPlugin::getProvisionRequest(Vector<uint8_t> &request,
250                                                String8 &defaultUrl)
251    {
252        Mutex::Autolock lock(mLock);
253        ALOGD("MockDrmPlugin::getProvisionRequest()");
254
255        // Properties used in mock test, set by cts test app returned from mock plugin
256        //   byte[] mock-request       -> request
257        //   string mock-default-url   -> defaultUrl
258
259        ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-request"));
260        if (index < 0) {
261            ALOGD("Missing 'mock-request' parameter for mock");
262            return BAD_VALUE;
263        } else {
264            request = mByteArrayProperties.valueAt(index);
265        }
266
267        index = mStringProperties.indexOfKey(String8("mock-defaultUrl"));
268        if (index < 0) {
269            ALOGD("Missing 'mock-defaultUrl' parameter for mock");
270            return BAD_VALUE;
271        } else {
272            defaultUrl = mStringProperties.valueAt(index);
273        }
274        return OK;
275    }
276
277    status_t MockDrmPlugin::provideProvisionResponse(Vector<uint8_t> const &response)
278    {
279        Mutex::Autolock lock(mLock);
280        ALOGD("MockDrmPlugin::provideProvisionResponse(%s)",
281              vectorToString(response).string());
282
283        // Properties used in mock test, set by mock plugin and verifed cts test app
284        //   byte[] response            -> mock-response
285
286        mByteArrayProperties.add(String8("mock-response"), response);
287        return OK;
288    }
289
290    status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
291    {
292        Mutex::Autolock lock(mLock);
293        ALOGD("MockDrmPlugin::getSecureStops()");
294        const uint8_t ss1[] = {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89};
295        const uint8_t ss2[] = {0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99};
296
297        Vector<uint8_t> vec;
298        vec.appendArray(ss1, sizeof(ss1));
299        secureStops.push_back(vec);
300
301        vec.clear();
302        vec.appendArray(ss2, sizeof(ss2));
303        secureStops.push_back(vec);
304        return OK;
305    }
306
307    status_t MockDrmPlugin::releaseSecureStops(Vector<uint8_t> const &ssRelease)
308    {
309        Mutex::Autolock lock(mLock);
310        ALOGD("MockDrmPlugin::releaseSecureStops(%s)",
311              vectorToString(ssRelease).string());
312        return OK;
313    }
314
315    status_t MockDrmPlugin::getPropertyString(String8 const &name, String8 &value) const
316    {
317        ALOGD("MockDrmPlugin::getPropertyString(name=%s)", name.string());
318        ssize_t index = mStringProperties.indexOfKey(name);
319        if (index < 0) {
320            ALOGD("no property for '%s'", name.string());
321            return BAD_VALUE;
322        }
323        value = mStringProperties.valueAt(index);
324        return OK;
325    }
326
327    status_t MockDrmPlugin::getPropertyByteArray(String8 const &name,
328                                                 Vector<uint8_t> &value) const
329    {
330        ALOGD("MockDrmPlugin::getPropertyByteArray(name=%s)", name.string());
331        ssize_t index = mByteArrayProperties.indexOfKey(name);
332        if (index < 0) {
333            ALOGD("no property for '%s'", name.string());
334            return BAD_VALUE;
335        }
336        value = mByteArrayProperties.valueAt(index);
337        return OK;
338    }
339
340    status_t MockDrmPlugin::setPropertyString(String8 const &name,
341                                              String8 const &value)
342    {
343        Mutex::Autolock lock(mLock);
344        ALOGD("MockDrmPlugin::setPropertyString(name=%s, value=%s)",
345              name.string(), value.string());
346
347        if (name == "mock-send-event") {
348            unsigned code, extra;
349            sscanf(value.string(), "%d %d", &code, &extra);
350            DrmPlugin::EventType eventType = (DrmPlugin::EventType)code;
351
352            Vector<uint8_t> const *pSessionId = NULL;
353            ssize_t index = mByteArrayProperties.indexOfKey(String8("mock-event-session-id"));
354            if (index >= 0) {
355                pSessionId = &mByteArrayProperties[index];
356            }
357
358            Vector<uint8_t> const *pData = NULL;
359            index = mByteArrayProperties.indexOfKey(String8("mock-event-data"));
360            if (index >= 0) {
361                pData = &mByteArrayProperties[index];
362            }
363            ALOGD("sending event from mock drm plugin: %d %d %s %s",
364                  (int)code, extra, pSessionId ? vectorToString(*pSessionId) : "{}",
365                  pData ? vectorToString(*pData) : "{}");
366
367            sendEvent(eventType, extra, pSessionId, pData);
368        } else {
369            mStringProperties.add(name, value);
370        }
371        return OK;
372    }
373
374    status_t MockDrmPlugin::setPropertyByteArray(String8 const &name,
375                                                 Vector<uint8_t> const &value)
376    {
377        Mutex::Autolock lock(mLock);
378        ALOGD("MockDrmPlugin::setPropertyByteArray(name=%s, value=%s)",
379              name.string(), vectorToString(value).string());
380        mByteArrayProperties.add(name, value);
381        return OK;
382    }
383
384    status_t MockDrmPlugin::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
385                                               String8 const &algorithm)
386    {
387        Mutex::Autolock lock(mLock);
388
389        ALOGD("MockDrmPlugin::setCipherAlgorithm(sessionId=%s, algorithm=%s)",
390              vectorToString(sessionId).string(), algorithm.string());
391
392        ssize_t index = findSession(sessionId);
393        if (index == kNotFound) {
394            ALOGD("Invalid sessionId");
395            return BAD_VALUE;
396        }
397
398        if (algorithm == "AES/CBC/NoPadding") {
399            return OK;
400        }
401        return BAD_VALUE;
402    }
403
404    status_t MockDrmPlugin::setMacAlgorithm(Vector<uint8_t> const &sessionId,
405                                            String8 const &algorithm)
406    {
407        Mutex::Autolock lock(mLock);
408
409        ALOGD("MockDrmPlugin::setMacAlgorithm(sessionId=%s, algorithm=%s)",
410              vectorToString(sessionId).string(), algorithm.string());
411
412        ssize_t index = findSession(sessionId);
413        if (index == kNotFound) {
414            ALOGD("Invalid sessionId");
415            return BAD_VALUE;
416        }
417
418        if (algorithm == "HmacSHA256") {
419            return OK;
420        }
421        return BAD_VALUE;
422    }
423
424    status_t MockDrmPlugin::encrypt(Vector<uint8_t> const &sessionId,
425                                    Vector<uint8_t> const &keyId,
426                                    Vector<uint8_t> const &input,
427                                    Vector<uint8_t> const &iv,
428                                    Vector<uint8_t> &output)
429    {
430        Mutex::Autolock lock(mLock);
431        ALOGD("MockDrmPlugin::encrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
432              vectorToString(sessionId).string(),
433              vectorToString(keyId).string(),
434              vectorToString(input).string(),
435              vectorToString(iv).string());
436
437        ssize_t index = findSession(sessionId);
438        if (index == kNotFound) {
439            ALOGD("Invalid sessionId");
440            return BAD_VALUE;
441        }
442
443        // Properties used in mock test, set by mock plugin and verifed cts test app
444        //   byte[] keyId              -> mock-keyid
445        //   byte[] input              -> mock-input
446        //   byte[] iv                 -> mock-iv
447        mByteArrayProperties.add(String8("mock-keyid"), keyId);
448        mByteArrayProperties.add(String8("mock-input"), input);
449        mByteArrayProperties.add(String8("mock-iv"), iv);
450
451        // Properties used in mock test, set by cts test app returned from mock plugin
452        //   byte[] mock-output        -> output
453        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
454        if (index < 0) {
455            ALOGD("Missing 'mock-request' parameter for mock");
456            return BAD_VALUE;
457        } else {
458            output = mByteArrayProperties.valueAt(index);
459        }
460        return OK;
461    }
462
463    status_t MockDrmPlugin::decrypt(Vector<uint8_t> const &sessionId,
464                                    Vector<uint8_t> const &keyId,
465                                    Vector<uint8_t> const &input,
466                                    Vector<uint8_t> const &iv,
467                                    Vector<uint8_t> &output)
468    {
469        Mutex::Autolock lock(mLock);
470        ALOGD("MockDrmPlugin::decrypt(sessionId=%s, keyId=%s, input=%s, iv=%s)",
471              vectorToString(sessionId).string(),
472              vectorToString(keyId).string(),
473              vectorToString(input).string(),
474              vectorToString(iv).string());
475
476        ssize_t index = findSession(sessionId);
477        if (index == kNotFound) {
478            ALOGD("Invalid sessionId");
479            return BAD_VALUE;
480        }
481
482        // Properties used in mock test, set by mock plugin and verifed cts test app
483        //   byte[] keyId              -> mock-keyid
484        //   byte[] input              -> mock-input
485        //   byte[] iv                 -> mock-iv
486        mByteArrayProperties.add(String8("mock-keyid"), keyId);
487        mByteArrayProperties.add(String8("mock-input"), input);
488        mByteArrayProperties.add(String8("mock-iv"), iv);
489
490        // Properties used in mock test, set by cts test app returned from mock plugin
491        //   byte[] mock-output        -> output
492        index = mByteArrayProperties.indexOfKey(String8("mock-output"));
493        if (index < 0) {
494            ALOGD("Missing 'mock-request' parameter for mock");
495            return BAD_VALUE;
496        } else {
497            output = mByteArrayProperties.valueAt(index);
498        }
499        return OK;
500    }
501
502    status_t MockDrmPlugin::sign(Vector<uint8_t> const &sessionId,
503                                 Vector<uint8_t> const &keyId,
504                                 Vector<uint8_t> const &message,
505                                 Vector<uint8_t> &signature)
506    {
507        Mutex::Autolock lock(mLock);
508        ALOGD("MockDrmPlugin::sign(sessionId=%s, keyId=%s, message=%s)",
509              vectorToString(sessionId).string(),
510              vectorToString(keyId).string(),
511              vectorToString(message).string());
512
513        ssize_t index = findSession(sessionId);
514        if (index == kNotFound) {
515            ALOGD("Invalid sessionId");
516            return BAD_VALUE;
517        }
518
519        // Properties used in mock test, set by mock plugin and verifed cts test app
520        //   byte[] keyId              -> mock-keyid
521        //   byte[] message            -> mock-message
522        mByteArrayProperties.add(String8("mock-keyid"), keyId);
523        mByteArrayProperties.add(String8("mock-message"), message);
524
525        // Properties used in mock test, set by cts test app returned from mock plugin
526        //   byte[] mock-signature        -> signature
527        index = mByteArrayProperties.indexOfKey(String8("mock-signature"));
528        if (index < 0) {
529            ALOGD("Missing 'mock-request' parameter for mock");
530            return BAD_VALUE;
531        } else {
532            signature = mByteArrayProperties.valueAt(index);
533        }
534        return OK;
535    }
536
537    status_t MockDrmPlugin::verify(Vector<uint8_t> const &sessionId,
538                                   Vector<uint8_t> const &keyId,
539                                   Vector<uint8_t> const &message,
540                                   Vector<uint8_t> const &signature,
541                                   bool &match)
542    {
543        Mutex::Autolock lock(mLock);
544        ALOGD("MockDrmPlugin::verify(sessionId=%s, keyId=%s, message=%s, signature=%s)",
545              vectorToString(sessionId).string(),
546              vectorToString(keyId).string(),
547              vectorToString(message).string(),
548              vectorToString(signature).string());
549
550        ssize_t index = findSession(sessionId);
551        if (index == kNotFound) {
552            ALOGD("Invalid sessionId");
553            return BAD_VALUE;
554        }
555
556        // Properties used in mock test, set by mock plugin and verifed cts test app
557        //   byte[] keyId              -> mock-keyid
558        //   byte[] message            -> mock-message
559        //   byte[] signature          -> mock-signature
560        mByteArrayProperties.add(String8("mock-keyid"), keyId);
561        mByteArrayProperties.add(String8("mock-message"), message);
562        mByteArrayProperties.add(String8("mock-signature"), signature);
563
564        // Properties used in mock test, set by cts test app returned from mock plugin
565        //   String mock-match "1" or "0"         -> match
566        index = mStringProperties.indexOfKey(String8("mock-match"));
567        if (index < 0) {
568            ALOGD("Missing 'mock-request' parameter for mock");
569            return BAD_VALUE;
570        } else {
571            match = atol(mStringProperties.valueAt(index).string());
572        }
573        return OK;
574    }
575
576    ssize_t MockDrmPlugin::findSession(Vector<uint8_t> const &sessionId) const
577    {
578        ALOGD("findSession: nsessions=%d, size=%d", mSessions.size(), sessionId.size());
579        for (size_t i = 0; i < mSessions.size(); ++i) {
580            if (memcmp(mSessions[i].array(), sessionId.array(), sessionId.size()) == 0) {
581                return i;
582            }
583        }
584        return kNotFound;
585    }
586
587    ssize_t MockDrmPlugin::findKeySet(Vector<uint8_t> const &keySetId) const
588    {
589        ALOGD("findKeySet: nkeySets=%d, size=%d", mKeySets.size(), keySetId.size());
590        for (size_t i = 0; i < mKeySets.size(); ++i) {
591            if (memcmp(mKeySets[i].array(), keySetId.array(), keySetId.size()) == 0) {
592                return i;
593            }
594        }
595        return kNotFound;
596    }
597
598
599    // Conversion utilities
600    String8 MockDrmPlugin::vectorToString(Vector<uint8_t> const &vector) const
601    {
602        return arrayToString(vector.array(), vector.size());
603    }
604
605    String8 MockDrmPlugin::arrayToString(uint8_t const *array, size_t len) const
606    {
607        String8 result("{ ");
608        for (size_t i = 0; i < len; i++) {
609            result.appendFormat("0x%02x ", array[i]);
610        }
611        result += "}";
612        return result;
613    }
614
615    String8 MockDrmPlugin::stringMapToString(KeyedVector<String8, String8> map) const
616    {
617        String8 result("{ ");
618        for (size_t i = 0; i < map.size(); i++) {
619            result.appendFormat("%s{name=%s, value=%s}", i > 0 ? ", " : "",
620                                map.keyAt(i).string(), map.valueAt(i).string());
621        }
622        return result + " }";
623    }
624
625    bool operator<(Vector<uint8_t> const &lhs, Vector<uint8_t> const &rhs) {
626        return lhs.size() < rhs.size() || (memcmp(lhs.array(), rhs.array(), lhs.size()) < 0);
627    }
628
629    //
630    // Crypto Plugin
631    //
632
633    bool MockCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const
634    {
635        ALOGD("MockCryptoPlugin::requiresSecureDecoderComponent(mime=%s)", mime);
636        return false;
637    }
638
639    ssize_t
640    MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
641                              Mode mode, const void *srcPtr, const SubSample *subSamples,
642                              size_t numSubSamples, void *dstPtr, AString *errorDetailMsg)
643    {
644        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
645              "subSamples=%s, dst=%p)",
646              (int)secure,
647              arrayToString(key, sizeof(key)).string(),
648              arrayToString(iv, sizeof(iv)).string(),
649              (int)mode, srcPtr,
650              subSamplesToString(subSamples, numSubSamples).string(),
651              dstPtr);
652        return OK;
653    }
654
655    // Conversion utilities
656    String8 MockCryptoPlugin::arrayToString(uint8_t const *array, size_t len) const
657    {
658        String8 result("{ ");
659        for (size_t i = 0; i < len; i++) {
660            result.appendFormat("0x%02x ", array[i]);
661        }
662        result += "}";
663        return result;
664    }
665
666    String8 MockCryptoPlugin::subSamplesToString(SubSample const *subSamples,
667                                                 size_t numSubSamples) const
668    {
669        String8 result;
670        for (size_t i = 0; i < numSubSamples; i++) {
671            result.appendFormat("[%d] {clear:%d, encrypted:%d} ", i,
672                                subSamples[i].mNumBytesOfClearData,
673                                subSamples[i].mNumBytesOfEncryptedData);
674        }
675        return result;
676    }
677
678};
679