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