• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package android.media.drmframework.cts;
18 
19 import android.media.MediaDrm;
20 import android.media.MediaDrm.CryptoSession;
21 import android.media.MediaDrm.KeyRequest;
22 import android.media.MediaDrm.KeyStatus;
23 import android.media.MediaDrm.ProvisionRequest;
24 import android.media.MediaDrmException;
25 import android.media.NotProvisionedException;
26 import android.media.ResourceBusyException;
27 import android.test.AndroidTestCase;
28 import android.util.Log;
29 import com.android.compatibility.common.util.FrameworkSpecificTest;
30 import java.util.HashMap;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.Iterator;
34 import java.util.UUID;
35 import java.util.concurrent.ScheduledThreadPoolExecutor;
36 import java.util.concurrent.ThreadPoolExecutor;
37 import java.util.concurrent.TimeUnit;
38 import java.lang.Thread;
39 import java.lang.Object;
40 import android.os.Looper;
41 
42 // This test works with the MediaDrm mock plugin
43 @FrameworkSpecificTest
44 public class MediaDrmMockTest extends AndroidTestCase
45         implements MediaDrm.OnEventListener, MediaDrm.OnKeyStatusChangeListener,
46         MediaDrm.OnExpirationUpdateListener, MediaDrm.OnSessionLostStateListener {
47     private static final String TAG = "MediaDrmMockTest";
48 
49     // The scheme supported by the mock drm plugin
50     static final UUID mockScheme = new UUID(0x0102030405060708L, 0x090a0b0c0d0e0f10L);
51     static final UUID badScheme = new UUID(0xffffffffffffffffL, 0xffffffffffffffffL);
52     static final UUID clearkeyScheme = new UUID(0xe2719d58a985b3c9L, 0x781ab030af78d30eL);
53 
isMockPluginInstalled()54     private boolean isMockPluginInstalled() {
55         return MediaDrm.isCryptoSchemeSupported(mockScheme);
56     }
57 
testIsCryptoSchemeNotSupported()58     public void testIsCryptoSchemeNotSupported() throws Exception {
59         assertFalse(MediaDrm.isCryptoSchemeSupported(badScheme));
60     }
61 
testMediaDrmConstructor()62     public void testMediaDrmConstructor() throws Exception {
63         if (isMockPluginInstalled()) {
64             MediaDrm md = new MediaDrm(mockScheme);
65         } else {
66             Log.w(TAG, "optional plugin libmockdrmcryptoplugin.so is not installed");
67             Log.w(TAG, "To verify the MediaDrm APIs, you should install this plugin");
68         }
69     }
70 
testIsMimeTypeSupported()71     public void testIsMimeTypeSupported() throws Exception {
72         if (!isMockPluginInstalled()) {
73             return;
74         }
75         String mimeType = "video/mp4";
76         assertTrue(MediaDrm.isCryptoSchemeSupported(mockScheme, mimeType));
77     }
78 
testIsMimeTypeNotSupported()79     public void testIsMimeTypeNotSupported() throws Exception {
80         if (!isMockPluginInstalled()) {
81             return;
82         }
83         String mimeType = "video/foo";
84         assertFalse(MediaDrm.isCryptoSchemeSupported(mockScheme, mimeType));
85     }
86 
testMediaDrmConstructorFails()87     public void testMediaDrmConstructorFails() throws Exception {
88         if (!isMockPluginInstalled()) {
89             return;
90         }
91 
92         boolean gotException = false;
93         try {
94             MediaDrm md = new MediaDrm(badScheme);
95         } catch (MediaDrmException e) {
96             gotException = true;
97         }
98         assertTrue(gotException);
99     }
100 
testStringProperties()101     public void testStringProperties() throws Exception {
102         if (!isMockPluginInstalled()) {
103             return;
104         }
105 
106         MediaDrm md = new MediaDrm(mockScheme);
107 
108         md.setPropertyString("test-string", "test-value");
109         assertTrue(md.getPropertyString("test-string").equals("test-value"));
110     }
111 
testByteArrayProperties()112     public void testByteArrayProperties() throws Exception {
113         if (!isMockPluginInstalled()) {
114             return;
115         }
116 
117         MediaDrm md = new MediaDrm(mockScheme);
118 
119         byte testArray[] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12};
120         md.setPropertyByteArray("test-array", testArray);
121         assertTrue(Arrays.equals(md.getPropertyByteArray("test-array"), testArray));
122     }
123 
testMissingPropertyString()124     public void testMissingPropertyString() throws Exception {
125         if (!isMockPluginInstalled()) {
126             return;
127         }
128 
129         MediaDrm md = new MediaDrm(mockScheme);
130 
131         boolean gotException = false;
132         try {
133             md.getPropertyString("missing-property");
134         } catch (IllegalArgumentException e) {
135             gotException = true;
136         }
137         assertTrue(gotException);
138     }
139 
testNullPropertyString()140     public void testNullPropertyString() throws Exception {
141         if (!isMockPluginInstalled()) {
142             return;
143         }
144 
145         MediaDrm md = new MediaDrm(mockScheme);
146 
147         boolean gotException = false;
148         try {
149             md.getPropertyString(null);
150         } catch (IllegalArgumentException e) {
151             gotException = true;
152         }
153         assertTrue(gotException);
154     }
155 
testMissingPropertyByteArray()156     public void testMissingPropertyByteArray() throws Exception {
157         if (!isMockPluginInstalled()) {
158             return;
159         }
160 
161         MediaDrm md = new MediaDrm(mockScheme);
162 
163         boolean gotException = false;
164         try {
165             md.getPropertyByteArray("missing-property");
166         } catch (IllegalArgumentException e) {
167             gotException = true;
168         }
169         assertTrue(gotException);
170     }
171 
testNullPropertyByteArray()172     public void testNullPropertyByteArray() throws Exception {
173         if (!isMockPluginInstalled()) {
174             return;
175         }
176 
177         MediaDrm md = new MediaDrm(mockScheme);
178 
179         boolean gotException = false;
180         try {
181             md.getPropertyByteArray(null);
182         } catch (IllegalArgumentException e) {
183             gotException = true;
184         }
185         assertTrue(gotException);
186     }
187 
testOpenCloseSession()188     public void testOpenCloseSession() throws Exception {
189         if (!isMockPluginInstalled()) {
190             return;
191         }
192 
193         MediaDrm md = new MediaDrm(mockScheme);
194         byte[] sessionId = openSession(md);
195         md.closeSession(sessionId);
196     }
197 
testBadSession()198     public void testBadSession() throws Exception {
199         if (!isMockPluginInstalled()) {
200             return;
201         }
202 
203         MediaDrm md = new MediaDrm(mockScheme);
204         byte[] sessionId = {0x05, 0x6, 0x7, 0x8};
205         boolean gotException = false;
206         try {
207             md.closeSession(sessionId);
208         } catch (IllegalArgumentException e) {
209             gotException = true;
210         }
211         assertTrue(gotException);
212     }
213 
testNullSession()214     public void testNullSession() throws Exception {
215         if (!isMockPluginInstalled()) {
216             return;
217         }
218 
219         MediaDrm md = new MediaDrm(mockScheme);
220         byte[] sessionId = null;
221         boolean gotException = false;
222         try {
223             md.closeSession(sessionId);
224         } catch (IllegalArgumentException e) {
225             gotException = true;
226         }
227         assertTrue(gotException);
228     }
229 
testGetKeyRequest()230     public void testGetKeyRequest() throws Exception {
231         if (!isMockPluginInstalled()) {
232             return;
233         }
234 
235         MediaDrm md = new MediaDrm(mockScheme);
236         byte[] sessionId = openSession(md);
237 
238         // Set up mock expected responses using properties
239         byte testRequest[] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12};
240         md.setPropertyByteArray("mock-request", testRequest);
241         String testDefaultUrl = "http://1.2.3.4:8080/blah";
242         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
243         md.setPropertyString("mock-keyRequestType", "1" /*kKeyRequestType_Initial*/);
244 
245         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
246         HashMap<String, String> optionalParameters = new HashMap<String, String>();
247         optionalParameters.put("param1", "value1");
248         optionalParameters.put("param2", "value2");
249 
250         String mimeType = "video/iso.segment";
251         KeyRequest request = md.getKeyRequest(sessionId, initData, mimeType,
252                                                       MediaDrm.KEY_TYPE_STREAMING,
253                                                       optionalParameters);
254         assertTrue(Arrays.equals(request.getData(), testRequest));
255         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
256         assertEquals(request.getRequestType(), MediaDrm.KeyRequest.REQUEST_TYPE_INITIAL);
257 
258         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
259         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
260         assertTrue(md.getPropertyString("mock-keytype").equals("1"));
261         assertTrue(md.getPropertyString("mock-optparams").equals("{param1,value1},{param2,value2}"));
262 
263         md.closeSession(sessionId);
264     }
265 
testGetKeyRequestNoOptionalParameters()266     public void testGetKeyRequestNoOptionalParameters() throws Exception {
267         if (!isMockPluginInstalled()) {
268             return;
269         }
270 
271         MediaDrm md = new MediaDrm(mockScheme);
272         byte[] sessionId = openSession(md);
273 
274         // Set up mock expected responses using properties
275         byte testRequest[] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12};
276         md.setPropertyByteArray("mock-request", testRequest);
277         String testDefaultUrl = "http://1.2.3.4:8080/blah";
278         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
279         md.setPropertyString("mock-keyRequestType", "1" /*kKeyRequestType_Initial*/);
280 
281         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
282 
283         String mimeType = "video/iso.segment";
284         KeyRequest request = md.getKeyRequest(sessionId, initData, mimeType,
285                                                       MediaDrm.KEY_TYPE_STREAMING,
286                                                       null);
287         assertTrue(Arrays.equals(request.getData(), testRequest));
288         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
289         assertEquals(request.getRequestType(), MediaDrm.KeyRequest.REQUEST_TYPE_INITIAL);
290 
291         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
292         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
293         assertTrue(md.getPropertyString("mock-keytype").equals("1"));
294 
295         md.closeSession(sessionId);
296     }
297 
testGetKeyRequestOffline()298     public void testGetKeyRequestOffline() throws Exception {
299         if (!isMockPluginInstalled()) {
300             return;
301         }
302 
303         MediaDrm md = new MediaDrm(mockScheme);
304         byte[] sessionId = openSession(md);
305 
306         // Set up mock expected responses using properties
307         byte testRequest[] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12};
308         md.setPropertyByteArray("mock-request", testRequest);
309         String testDefaultUrl = "http://1.2.3.4:8080/blah";
310         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
311         md.setPropertyString("mock-keyRequestType", "2" /*kKeyRequestType_Renewal*/);
312 
313         byte[] initData = {0x0a, 0x0b, 0x0c, 0x0d};
314 
315         String mimeType = "video/iso.segment";
316         KeyRequest request = md.getKeyRequest(sessionId, initData, mimeType,
317                                               MediaDrm.KEY_TYPE_OFFLINE,
318                                               null);
319         assertTrue(Arrays.equals(request.getData(), testRequest));
320         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
321         assertEquals(request.getRequestType(), MediaDrm.KeyRequest.REQUEST_TYPE_RENEWAL);
322 
323         assertTrue(Arrays.equals(initData, md.getPropertyByteArray("mock-initdata")));
324         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
325         assertTrue(md.getPropertyString("mock-keytype").equals("0"));
326 
327         md.closeSession(sessionId);
328     }
329 
testGetKeyRequestRelease()330     public void testGetKeyRequestRelease() throws Exception {
331         if (!isMockPluginInstalled()) {
332             return;
333         }
334 
335         MediaDrm md = new MediaDrm(mockScheme);
336         byte[] sessionId = openSession(md);
337 
338         // Set up mock expected responses using properties
339         byte testRequest[] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12};
340         md.setPropertyByteArray("mock-request", testRequest);
341         String testDefaultUrl = "http://1.2.3.4:8080/blah";
342         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
343         md.setPropertyString("mock-keyRequestType", "3" /*kKeyRequestType_Release*/);
344 
345         String mimeType = "video/iso.segment";
346         KeyRequest request = md.getKeyRequest(sessionId, null, mimeType,
347                                               MediaDrm.KEY_TYPE_RELEASE,
348                                               null);
349         assertTrue(Arrays.equals(request.getData(), testRequest));
350         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
351         assertEquals(request.getRequestType(), MediaDrm.KeyRequest.REQUEST_TYPE_RELEASE);
352 
353         assertTrue(mimeType.equals(md.getPropertyString("mock-mimetype")));
354         assertTrue(md.getPropertyString("mock-keytype").equals("2"));
355 
356         md.closeSession(sessionId);
357     }
358 
testProvideKeyResponse()359     public void testProvideKeyResponse() throws Exception {
360         if (!isMockPluginInstalled()) {
361             return;
362         }
363 
364         MediaDrm md = new MediaDrm(mockScheme);
365         byte[] sessionId = openSession(md);
366 
367         // Set up mock expected responses using properties
368         byte testResponse[] = {0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
369 
370         md.provideKeyResponse(sessionId, testResponse);
371 
372         assertTrue(Arrays.equals(testResponse, md.getPropertyByteArray("mock-response")));
373         md.closeSession(sessionId);
374     }
375 
testRemoveKeys()376     public void testRemoveKeys() throws Exception {
377         if (!isMockPluginInstalled()) {
378             return;
379         }
380 
381         MediaDrm md = new MediaDrm(mockScheme);
382         byte[] sessionId = openSession(md);
383 
384         byte testResponse[] = {0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
385         byte[] keySetId = md.provideKeyResponse(sessionId, testResponse);
386         md.closeSession(sessionId);
387 
388         md.removeKeys(keySetId);
389     }
390 
testRestoreKeys()391     public void testRestoreKeys() throws Exception {
392         if (!isMockPluginInstalled()) {
393             return;
394         }
395 
396         MediaDrm md = new MediaDrm(mockScheme);
397         byte[] sessionId = openSession(md);
398 
399         byte testResponse[] = {0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
400         byte[] keySetId = md.provideKeyResponse(sessionId, testResponse);
401         md.closeSession(sessionId);
402 
403         sessionId = openSession(md);
404         md.restoreKeys(sessionId, keySetId);
405         md.closeSession(sessionId);
406     }
407 
testQueryKeyStatus()408     public void testQueryKeyStatus() throws Exception {
409         if (!isMockPluginInstalled()) {
410             return;
411         }
412 
413         MediaDrm md = new MediaDrm(mockScheme);
414         byte[] sessionId = openSession(md);
415         HashMap<String, String> infoMap = md.queryKeyStatus(sessionId);
416 
417         // these are canned strings returned by the mock
418         assertTrue(infoMap.containsKey("purchaseDuration"));
419         assertTrue(infoMap.get("purchaseDuration").equals(("1000")));
420         assertTrue(infoMap.containsKey("licenseDuration"));
421         assertTrue(infoMap.get("licenseDuration").equals(("100")));
422 
423         md.closeSession(sessionId);
424     }
425 
testGetProvisionRequest()426     public void testGetProvisionRequest() throws Exception {
427         if (!isMockPluginInstalled()) {
428             return;
429         }
430 
431         MediaDrm md = new MediaDrm(mockScheme);
432 
433         // Set up mock expected responses using properties
434         byte testRequest[] = {0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x60, 0x61, 0x62};
435         md.setPropertyByteArray("mock-request", testRequest);
436         String testDefaultUrl = "http://1.2.3.4:8080/bar";
437         md.setPropertyString("mock-defaultUrl", testDefaultUrl);
438 
439         ProvisionRequest request = md.getProvisionRequest();
440         assertTrue(Arrays.equals(request.getData(), testRequest));
441         assertTrue(request.getDefaultUrl().equals(testDefaultUrl));
442     }
443 
testProvideProvisionResponse()444     public void testProvideProvisionResponse() throws Exception {
445         if (!isMockPluginInstalled()) {
446             return;
447         }
448 
449         MediaDrm md = new MediaDrm(mockScheme);
450 
451         // Set up mock expected responses using properties
452         byte testResponse[] = {0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
453 
454         md.provideProvisionResponse(testResponse);
455         assertTrue(Arrays.equals(testResponse, md.getPropertyByteArray("mock-response")));
456     }
457 
testGetSecureStops()458     public void testGetSecureStops() throws Exception {
459         if (!isMockPluginInstalled()) {
460             return;
461         }
462 
463         MediaDrm md = new MediaDrm(mockScheme);
464 
465         // Set up mock expected responses using properties
466         byte ss1[] = {0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20};
467         byte ss2[] = {0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30};
468 
469         md.setPropertyByteArray("mock-secure-stop1", ss1);
470         md.setPropertyByteArray("mock-secure-stop2", ss2);
471 
472         List<byte[]> secureStopList = md.getSecureStops();
473         assertTrue(secureStopList != null);
474 
475         Iterator<byte[]> iter = secureStopList.iterator();
476         assertTrue(iter.hasNext());
477         assertTrue(Arrays.equals(iter.next(), ss1));
478         assertTrue(iter.hasNext());
479         assertTrue(Arrays.equals(iter.next(), ss2));
480         assertFalse(iter.hasNext());
481     }
482 
testReleaseSecureStops()483     public void testReleaseSecureStops() throws Exception {
484         if (!isMockPluginInstalled()) {
485             return;
486         }
487 
488         MediaDrm md = new MediaDrm(mockScheme);
489 
490         // Set up mock expected responses using properties
491         byte ssrelease[] = {0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40};
492 
493         md.releaseSecureStops(ssrelease);
494         assertTrue(Arrays.equals(ssrelease, md.getPropertyByteArray("mock-ssrelease")));
495     }
496 
testMultipleSessions()497     public void testMultipleSessions() throws Exception {
498         if (!isMockPluginInstalled()) {
499             return;
500         }
501 
502         MediaDrm md = new MediaDrm(mockScheme);
503 
504         byte[] session1 = openSession(md);
505         byte[] session2 = openSession(md);
506         byte[] session3 = openSession(md);
507 
508         assertFalse(Arrays.equals(session1, session2));
509         assertFalse(Arrays.equals(session2, session3));
510 
511         md.closeSession(session1);
512         md.closeSession(session2);
513         md.closeSession(session3);
514     }
515 
testCryptoSession()516     public void testCryptoSession() throws Exception {
517         if (!isMockPluginInstalled()) {
518             return;
519         }
520 
521         MediaDrm md = new MediaDrm(mockScheme);
522 
523         byte[] sessionId = openSession(md);
524         CryptoSession cs = md.getCryptoSession(sessionId, "AES/CBC/NoPadding", "HmacSHA256");
525         assertFalse(cs == null);
526     }
527 
testBadCryptoSession()528     public void testBadCryptoSession() throws Exception {
529         if (!isMockPluginInstalled()) {
530             return;
531         }
532 
533         MediaDrm md = new MediaDrm(mockScheme);
534 
535         boolean gotException = false;
536         try {
537             byte[] sessionId = openSession(md);
538             CryptoSession cs = md.getCryptoSession(sessionId, "bad", "bad");
539         } catch (IllegalArgumentException e) {
540             gotException = true;
541         }
542         assertTrue(gotException);
543     }
544 
testCryptoSessionEncrypt()545     public void testCryptoSessionEncrypt() throws Exception {
546         if (!isMockPluginInstalled()) {
547             return;
548         }
549 
550         MediaDrm md = new MediaDrm(mockScheme);
551 
552         byte[] sessionId = openSession(md);
553         CryptoSession cs = md.getCryptoSession(sessionId, "AES/CBC/NoPadding", "HmacSHA256");
554         assertFalse(cs == null);
555 
556         byte[] keyId = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
557         byte[] input = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
558         byte[] iv = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
559         byte[] expected_output = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
560 
561         md.setPropertyByteArray("mock-output", expected_output);
562 
563         byte[] output = cs.encrypt(keyId, input, iv);
564 
565         assertTrue(Arrays.equals(keyId, md.getPropertyByteArray("mock-keyid")));
566         assertTrue(Arrays.equals(input, md.getPropertyByteArray("mock-input")));
567         assertTrue(Arrays.equals(iv, md.getPropertyByteArray("mock-iv")));
568         assertTrue(Arrays.equals(output, expected_output));
569     }
570 
testCryptoSessionDecrypt()571     public void testCryptoSessionDecrypt() throws Exception {
572         if (!isMockPluginInstalled()) {
573             return;
574         }
575 
576         MediaDrm md = new MediaDrm(mockScheme);
577 
578         byte[] sessionId = openSession(md);
579         CryptoSession cs = md.getCryptoSession(sessionId, "AES/CBC/NoPadding", "HmacSHA256");
580         assertFalse(cs == null);
581 
582         byte[] keyId = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49};
583         byte[] input = {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59};
584         byte[] iv = {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69};
585         byte[] expected_output = {0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79};
586 
587         md.setPropertyByteArray("mock-output", expected_output);
588 
589         byte[] output = cs.decrypt(keyId, input, iv);
590 
591         assertTrue(Arrays.equals(keyId, md.getPropertyByteArray("mock-keyid")));
592         assertTrue(Arrays.equals(input, md.getPropertyByteArray("mock-input")));
593         assertTrue(Arrays.equals(iv, md.getPropertyByteArray("mock-iv")));
594         assertTrue(Arrays.equals(output, expected_output));
595     }
596 
testCryptoSessionSign()597     public void testCryptoSessionSign() throws Exception {
598         if (!isMockPluginInstalled()) {
599             return;
600         }
601 
602         MediaDrm md = new MediaDrm(mockScheme);
603 
604         byte[] sessionId = openSession(md);
605         CryptoSession cs = md.getCryptoSession(sessionId, "AES/CBC/NoPadding", "HmacSHA256");
606         assertFalse(cs == null);
607 
608         byte[] keyId = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
609         byte[] message = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
610         byte[] expected_signature = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
611 
612         md.setPropertyByteArray("mock-signature", expected_signature);
613 
614         byte[] signature = cs.sign(keyId, message);
615 
616         assertTrue(Arrays.equals(keyId, md.getPropertyByteArray("mock-keyid")));
617         assertTrue(Arrays.equals(message, md.getPropertyByteArray("mock-message")));
618         assertTrue(Arrays.equals(signature, expected_signature));
619     }
620 
testCryptoSessionVerify()621     public void testCryptoSessionVerify() throws Exception {
622         if (!isMockPluginInstalled()) {
623             return;
624         }
625 
626         MediaDrm md = new MediaDrm(mockScheme);
627 
628         byte[] sessionId = openSession(md);
629         CryptoSession cs = md.getCryptoSession(sessionId, "AES/CBC/NoPadding", "HmacSHA256");
630         assertFalse(cs == null);
631 
632         byte[] keyId = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49};
633         byte[] message = {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59};
634         byte[] signature = {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69};
635 
636         md.setPropertyString("mock-match", "1");
637         assertTrue(cs.verify(keyId, message, signature));
638 
639         assertTrue(Arrays.equals(keyId, md.getPropertyByteArray("mock-keyid")));
640         assertTrue(Arrays.equals(message, md.getPropertyByteArray("mock-message")));
641         assertTrue(Arrays.equals(signature, md.getPropertyByteArray("mock-signature")));
642 
643         md.setPropertyString("mock-match", "0");
644         assertFalse(cs.verify(keyId, message, signature));
645     }
646 
647     private MediaDrm mMediaDrm = null;
648     private Looper mLooper = null;
649     private Object mLock = new Object();
650     private boolean mGotEvent = false;
651 
652     private int mExpectedEvent;
653     private byte[] mExpectedSessionId;
654     private byte[] mExpectedData;
655 
656     private ThreadPoolExecutor mExecutor;
657 
658     @Override
onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data)659     public void onEvent(MediaDrm md, byte[] sessionId, int event,
660                         int extra, byte[] data) {
661         synchronized(mLock) {
662             Log.d(TAG,"testEventNoSessionNoData.onEvent");
663             assertTrue(md == mMediaDrm);
664             assertTrue(event == mExpectedEvent);
665             assertTrue(Arrays.equals(sessionId, mExpectedSessionId));
666             assertTrue(Arrays.equals(data, mExpectedData));
667             mGotEvent = true;
668             mLock.notify();
669         }
670     }
671 
testEventNoSessionNoDataWithExecutor()672     public void testEventNoSessionNoDataWithExecutor() throws Exception {
673         mExecutor = new ScheduledThreadPoolExecutor(1);
674         testEventNoSessionNoData();
675     }
676 
testEventNoSessionNoData()677     public void testEventNoSessionNoData() throws Exception {
678         if (!isMockPluginInstalled()) {
679             return;
680         }
681 
682         mExpectedEvent = 2;
683 
684         new Thread() {
685             @Override
686             public void run() {
687                 // Set up a looper to be used by mMediaPlayer.
688                 Looper.prepare();
689 
690                 // Save the looper so that we can terminate this thread
691                 // after we are done with it.
692                 mLooper = Looper.myLooper();
693 
694                 try {
695                     mMediaDrm = new MediaDrm(mockScheme);
696                 } catch (MediaDrmException e) {
697                     e.printStackTrace();
698                     fail();
699                 }
700 
701                 synchronized(mLock) {
702                     mLock.notify();
703                     if (mExecutor != null) {
704                         mMediaDrm.setOnEventListener(mExecutor, MediaDrmMockTest.this);
705                     } else {
706                         mMediaDrm.setOnEventListener(MediaDrmMockTest.this);
707                     }
708                 }
709 
710                 Looper.loop();  // Blocks forever until Looper.quit() is called.
711             }
712         }.start();
713 
714         // wait for mMediaDrm to be created
715         synchronized(mLock) {
716             try {
717                 mLock.wait(1000);
718             } catch (Exception e) {
719             }
720         }
721         assertTrue(mMediaDrm != null);
722 
723         mGotEvent = false;
724         mMediaDrm.setPropertyString("mock-send-event", "2 456");
725 
726         synchronized(mLock) {
727             try {
728                 mLock.wait(1000);
729             } catch (Exception e) {
730             }
731         }
732 
733         mLooper.quit();
734         assertTrue(mGotEvent);
735         shutdownExecutor();
736     }
737 
testEventWithSessionAndDataWithExecutor()738     public void testEventWithSessionAndDataWithExecutor() throws Exception {
739         mExecutor = new ScheduledThreadPoolExecutor(1);
740         testEventWithSessionAndData();
741     }
742 
testEventWithSessionAndData()743     public void testEventWithSessionAndData() throws Exception {
744         if (!isMockPluginInstalled()) {
745             return;
746         }
747 
748 
749         new Thread() {
750             @Override
751             public void run() {
752                 // Set up a looper to be used by mMediaPlayer.
753                 Looper.prepare();
754 
755                 // Save the looper so that we can terminate this thread
756                 // after we are done with it.
757                 mLooper = Looper.myLooper();
758 
759                 try {
760                     mMediaDrm = new MediaDrm(mockScheme);
761                 } catch (MediaDrmException e) {
762                     e.printStackTrace();
763                     fail();
764                 }
765 
766 
767                 mExpectedEvent = 1;
768                 mExpectedSessionId = openSession(mMediaDrm);
769                 mExpectedData = new byte[] {0x10, 0x11, 0x12, 0x13, 0x14,
770                                               0x15, 0x16, 0x17, 0x18, 0x19};
771 
772                 mMediaDrm.setPropertyByteArray("mock-event-session-id", mExpectedSessionId);
773                 mMediaDrm.setPropertyByteArray("mock-event-data", mExpectedData);
774 
775                 synchronized(mLock) {
776                     mLock.notify();
777                     if (mExecutor != null) {
778                         mMediaDrm.setOnEventListener(mExecutor, MediaDrmMockTest.this);
779                     } else {
780                         mMediaDrm.setOnEventListener(MediaDrmMockTest.this);
781                     }
782                 }
783                 Looper.loop();  // Blocks forever until Looper.quit() is called.
784             }
785         }.start();
786 
787         // wait for mMediaDrm to be created
788         synchronized(mLock) {
789             try {
790                 mLock.wait(1000);
791             } catch (Exception e) {
792             }
793         }
794         assertTrue(mMediaDrm != null);
795 
796         mGotEvent = false;
797         mMediaDrm.setPropertyString("mock-send-event", "1 123");
798 
799         synchronized(mLock) {
800             try {
801                 mLock.wait(1000);
802             } catch (Exception e) {
803             }
804         }
805 
806         mLooper.quit();
807         assertTrue(mGotEvent);
808         shutdownExecutor();
809     }
810 
811     @Override
onExpirationUpdate(MediaDrm md, byte[] sessionId, long expiryTimeMS)812     public void onExpirationUpdate(MediaDrm md, byte[] sessionId,
813             long expiryTimeMS) {
814         synchronized(mLock) {
815             Log.d(TAG,"testExpirationUpdate.onExpirationUpdate");
816             assertTrue(md == mMediaDrm);
817             assertTrue(Arrays.equals(sessionId, mExpectedSessionId));
818             assertTrue(expiryTimeMS == 123456789012345L);
819             mGotEvent = true;
820             mLock.notify();
821         }
822     }
823 
testExpirationUpdateWithExecutor()824     public void testExpirationUpdateWithExecutor() throws Exception {
825         mExecutor = new ScheduledThreadPoolExecutor(1);
826         testExpirationUpdate();
827     }
828 
testExpirationUpdate()829     public void testExpirationUpdate() throws Exception {
830         if (!isMockPluginInstalled()) {
831             return;
832         }
833 
834 
835         new Thread() {
836             @Override
837             public void run() {
838                 // Set up a looper to be used by mMediaPlayer.
839                 Looper.prepare();
840 
841                 // Save the looper so that we can terminate this thread
842                 // after we are done with it.
843                 mLooper = Looper.myLooper();
844 
845                 try {
846                     mMediaDrm = new MediaDrm(mockScheme);
847                 } catch (MediaDrmException e) {
848                     e.printStackTrace();
849                     fail();
850                 }
851 
852 
853                 mExpectedSessionId = openSession(mMediaDrm);
854 
855                 mMediaDrm.setPropertyByteArray("mock-event-session-id", mExpectedSessionId);
856 
857                 synchronized(mLock) {
858                     mLock.notify();
859                     if (mExecutor != null) {
860                         mMediaDrm.setOnExpirationUpdateListener(mExecutor, MediaDrmMockTest.this);
861                     } else {
862                         mMediaDrm.setOnExpirationUpdateListener(MediaDrmMockTest.this, null);
863                     }
864                 }
865                 Looper.loop();  // Blocks forever until Looper.quit() is called.
866             }
867         }.start();
868 
869         // wait for mMediaDrm to be created
870         synchronized(mLock) {
871             try {
872                 mLock.wait(1000);
873             } catch (Exception e) {
874             }
875         }
876         assertTrue(mMediaDrm != null);
877 
878         mGotEvent = false;
879         mMediaDrm.setPropertyString("mock-send-expiration-update", "123456789012345");
880 
881         synchronized(mLock) {
882             try {
883                 mLock.wait(1000);
884             } catch (Exception e) {
885             }
886         }
887 
888         mLooper.quit();
889         assertTrue(mGotEvent);
890         shutdownExecutor();
891     }
892 
893     @Override
onKeyStatusChange(MediaDrm md, byte[] sessionId, List<KeyStatus> keyInformation, boolean hasNewUsableKey)894     public void onKeyStatusChange(MediaDrm md, byte[] sessionId,
895             List<KeyStatus> keyInformation, boolean hasNewUsableKey) {
896         synchronized(mLock) {
897             Log.d(TAG,"testKeyStatusChange.onKeyStatusChange");
898             assertTrue(md == mMediaDrm);
899             assertTrue(Arrays.equals(sessionId, mExpectedSessionId));
900             try {
901                 KeyStatus keyStatus = keyInformation.get(0);
902                 assertTrue(Arrays.equals(keyStatus.getKeyId(), "key1".getBytes()));
903                 assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_USABLE);
904                 keyStatus = keyInformation.get(1);
905                 assertTrue(Arrays.equals(keyStatus.getKeyId(), "key2".getBytes()));
906                 assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_EXPIRED);
907                 keyStatus = keyInformation.get(2);
908                 assertTrue(Arrays.equals(keyStatus.getKeyId(), "key3".getBytes()));
909                 assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_OUTPUT_NOT_ALLOWED);
910                 keyStatus = keyInformation.get(3);
911                 assertTrue(Arrays.equals(keyStatus.getKeyId(), "key4".getBytes()));
912                 assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_PENDING);
913                 keyStatus = keyInformation.get(4);
914                 assertTrue(Arrays.equals(keyStatus.getKeyId(), "key5".getBytes()));
915                 assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_INTERNAL_ERROR);
916                 assertTrue(hasNewUsableKey);
917                 mGotEvent = true;
918             } catch (IndexOutOfBoundsException e) {
919             }
920             mLock.notify();
921         }
922     }
923 
testKeyStatusChangeWithExecutor()924     public void testKeyStatusChangeWithExecutor() throws Exception {
925         mExecutor = new ScheduledThreadPoolExecutor(1);
926         testKeyStatusChange();
927     }
928 
testKeyStatusChange()929     public void testKeyStatusChange() throws Exception {
930         if (!isMockPluginInstalled()) {
931             return;
932         }
933 
934 
935         new Thread() {
936             @Override
937             public void run() {
938                 // Set up a looper to be used by mMediaPlayer.
939                 Looper.prepare();
940 
941                 // Save the looper so that we can terminate this thread
942                 // after we are done with it.
943                 mLooper = Looper.myLooper();
944 
945                 try {
946                     mMediaDrm = new MediaDrm(mockScheme);
947                 } catch (MediaDrmException e) {
948                     e.printStackTrace();
949                     fail();
950                 }
951 
952 
953                 mExpectedSessionId = openSession(mMediaDrm);
954 
955                 mMediaDrm.setPropertyByteArray("mock-event-session-id", mExpectedSessionId);
956 
957                 synchronized(mLock) {
958                     mLock.notify();
959                     if (mExecutor != null) {
960                         mMediaDrm.setOnKeyStatusChangeListener(mExecutor, MediaDrmMockTest.this);
961                     } else {
962                         mMediaDrm.setOnKeyStatusChangeListener(MediaDrmMockTest.this, null);
963                     }
964                 }
965                 Looper.loop();  // Blocks forever until Looper.quit() is called.
966             }
967         }.start();
968 
969         // wait for mMediaDrm to be created
970         synchronized(mLock) {
971             try {
972                 mLock.wait(1000);
973             } catch (Exception e) {
974             }
975         }
976         assertTrue(mMediaDrm != null);
977 
978         mGotEvent = false;
979         mMediaDrm.setPropertyString("mock-send-keys-change", "123456789012345");
980 
981         synchronized(mLock) {
982             try {
983                 mLock.wait(1000);
984             } catch (Exception e) {
985             }
986         }
987 
988         mLooper.quit();
989         assertTrue(mGotEvent);
990         shutdownExecutor();
991     }
992 
993     @Override
onSessionLostState(MediaDrm md, byte[] sessionId)994     public void onSessionLostState(MediaDrm md, byte[] sessionId) {
995         assertTrue(md == mMediaDrm);
996         assertTrue(Arrays.equals(sessionId, mExpectedSessionId));
997         mGotEvent = true;
998         synchronized (mLock) {
999             mLock.notify();
1000         }
1001     }
1002 
testSessionLostStateWithExecutor()1003     public void testSessionLostStateWithExecutor() throws Exception {
1004         mExecutor = new ScheduledThreadPoolExecutor(1);
1005         testSessionLostState();
1006     }
1007 
testSessionLostState()1008     public void testSessionLostState() throws Exception {
1009         if (!MediaDrm.isCryptoSchemeSupported(clearkeyScheme)) {
1010             return;
1011         }
1012 
1013         try {
1014             mMediaDrm = new MediaDrm(clearkeyScheme);
1015         } catch (MediaDrmException e) {
1016             e.printStackTrace();
1017             fail();
1018         }
1019 
1020         mMediaDrm.setPropertyString("drmErrorTest", "lostState");
1021         if (mExecutor != null) {
1022             mMediaDrm.setOnSessionLostStateListener(mExecutor, this);
1023         } else {
1024             mMediaDrm.setOnSessionLostStateListener(this, null);
1025         }
1026 
1027         mGotEvent = false;
1028         mExpectedSessionId = openSession(mMediaDrm);
1029         try {
1030             mMediaDrm.closeSession(mExpectedSessionId);
1031         } catch (Exception err) {
1032             // expected
1033         }
1034 
1035         synchronized(mLock) {
1036             try {
1037                 mLock.wait(1000);
1038             } catch (Exception e) {
1039             }
1040         }
1041 
1042         assertTrue(mGotEvent);
1043         shutdownExecutor();
1044     }
1045 
openSession(MediaDrm md)1046     private byte[] openSession(MediaDrm md) {
1047         byte[] sessionId = null;
1048         try {
1049             sessionId = md.openSession();
1050         } catch (NotProvisionedException e) {
1051             // ignore, not thrown by mock
1052         } catch (ResourceBusyException e) {
1053             // ignore, not thrown by mock
1054         }
1055         return sessionId;
1056     }
1057 
shutdownExecutor()1058     private void shutdownExecutor() {
1059         if (mExecutor != null) {
1060             mExecutor.shutdown();
1061             try {
1062                 if (!mExecutor.awaitTermination(1, TimeUnit.SECONDS)) {
1063                     fail("timed out waiting for executor");
1064                 }
1065             } catch (InterruptedException e) {
1066                 fail("interrupted waiting for executor");
1067             }
1068             if (mExecutor.getTaskCount() == 0) {
1069                 fail("no tasks submitted");
1070             }
1071         }
1072     }
1073 }
1074