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; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.StringDef; 24 import android.app.ActivityThread; 25 import android.app.Application; 26 import android.compat.annotation.UnsupportedAppUsage; 27 import android.content.pm.PackageInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.Signature; 30 import android.media.metrics.LogSessionId; 31 import android.os.Handler; 32 import android.os.HandlerExecutor; 33 import android.os.Looper; 34 import android.os.Parcel; 35 import android.os.PersistableBundle; 36 import android.util.Log; 37 38 import dalvik.system.CloseGuard; 39 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.lang.ref.WeakReference; 43 import java.nio.ByteBuffer; 44 import java.time.Instant; 45 import java.security.MessageDigest; 46 import java.security.NoSuchAlgorithmException; 47 import java.util.ArrayList; 48 import java.util.Base64; 49 import java.util.HashMap; 50 import java.util.LinkedHashSet; 51 import java.util.List; 52 import java.util.Map; 53 import java.util.Objects; 54 import java.util.Set; 55 import java.util.UUID; 56 import java.util.concurrent.ConcurrentHashMap; 57 import java.util.concurrent.Executor; 58 import java.util.concurrent.atomic.AtomicBoolean; 59 import java.util.function.Consumer; 60 import java.util.function.Function; 61 62 /** 63 * MediaDrm can be used to obtain keys for decrypting protected media streams, in 64 * conjunction with {@link android.media.MediaCrypto}. The MediaDrm APIs 65 * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but 66 * may also be used to implement other encryption schemes. 67 * <p> 68 * Encrypted content is prepared using an encryption server and stored in a content 69 * library. The encrypted content is streamed or downloaded from the content library to 70 * client devices via content servers. Licenses to view the content are obtained from 71 * a License Server. 72 * <p> 73 * <p><img src="../../../images/mediadrm_overview.png" 74 * alt="MediaDrm Overview diagram" 75 * border="0" /></p> 76 * <p> 77 * Keys are requested from the license server using a key request. The key 78 * response is delivered to the client app, which provides the response to the 79 * MediaDrm API. 80 * <p> 81 * A Provisioning server may be required to distribute device-unique credentials to 82 * the devices. 83 * <p> 84 * Enforcing requirements related to the number of devices that may play content 85 * simultaneously can be performed either through key renewal or using the secure 86 * stop methods. 87 * <p> 88 * The following sequence diagram shows the interactions between the objects 89 * involved while playing back encrypted content: 90 * <p> 91 * <p><img src="../../../images/mediadrm_decryption_sequence.png" 92 * alt="MediaDrm Overview diagram" 93 * border="0" /></p> 94 * <p> 95 * The app first constructs {@link android.media.MediaExtractor} and 96 * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID, 97 * typically from metadata in the content, and uses this UUID to construct an instance 98 * of a MediaDrm object that is able to support the DRM scheme required by the content. 99 * Crypto schemes are assigned 16 byte UUIDs. The method {@link #isCryptoSchemeSupported} 100 * can be used to query if a given scheme is supported on the device. 101 * <p> 102 * The app calls {@link #openSession} to generate a sessionId that will uniquely identify 103 * the session in subsequent interactions. The app next uses the MediaDrm object to 104 * obtain a key request message and send it to the license server, then provide 105 * the server's response to the MediaDrm object. 106 * <p> 107 * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and 108 * sessionId. The MediaCrypto object is registered with the MediaCodec in the 109 * {@link MediaCodec#configure} method to enable the codec to decrypt content. 110 * <p> 111 * When the app has constructed {@link android.media.MediaExtractor}, 112 * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects, 113 * it proceeds to pull samples from the extractor and queue them into the decoder. For 114 * encrypted content, the samples returned from the extractor remain encrypted, they 115 * are only decrypted when the samples are delivered to the decoder. 116 * <p> 117 * MediaDrm methods throw {@link android.media.MediaDrm.MediaDrmStateException} 118 * when a method is called on a MediaDrm object that has had an unrecoverable failure 119 * in the DRM plugin or security hardware. 120 * {@link android.media.MediaDrm.MediaDrmStateException} extends 121 * {@link java.lang.IllegalStateException} with the addition of a developer-readable 122 * diagnostic information string associated with the exception. 123 * <p> 124 * In the event of a mediaserver process crash or restart while a MediaDrm object 125 * is active, MediaDrm methods may throw {@link android.media.MediaDrmResetException}. 126 * To recover, the app must release the MediaDrm object, then create and initialize 127 * a new one. 128 * <p> 129 * As {@link android.media.MediaDrmResetException} and 130 * {@link android.media.MediaDrm.MediaDrmStateException} both extend 131 * {@link java.lang.IllegalStateException}, they should be in an earlier catch() 132 * block than {@link java.lang.IllegalStateException} if handled separately. 133 * <p> 134 * <a name="Callbacks"></a> 135 * <h3>Callbacks</h3> 136 * <p>Applications should register for informational events in order 137 * to be informed of key state updates during playback or streaming. 138 * Registration for these events is done via a call to 139 * {@link #setOnEventListener}. In order to receive the respective 140 * callback associated with this listener, applications are required to create 141 * MediaDrm objects on a thread with its own Looper running (main UI 142 * thread by default has a Looper running). 143 */ 144 public final class MediaDrm implements AutoCloseable { 145 146 private static final String TAG = "MediaDrm"; 147 148 private final AtomicBoolean mClosed = new AtomicBoolean(); 149 private final CloseGuard mCloseGuard = CloseGuard.get(); 150 151 private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; 152 153 private long mNativeContext; 154 private final String mAppPackageName; 155 156 /** 157 * Specify no certificate type 158 * 159 * @hide - not part of the public API at this time 160 */ 161 public static final int CERTIFICATE_TYPE_NONE = 0; 162 163 /** 164 * Specify X.509 certificate type 165 * 166 * @hide - not part of the public API at this time 167 */ 168 public static final int CERTIFICATE_TYPE_X509 = 1; 169 170 /** @hide */ 171 @IntDef({ 172 CERTIFICATE_TYPE_NONE, 173 CERTIFICATE_TYPE_X509, 174 }) 175 @Retention(RetentionPolicy.SOURCE) 176 public @interface CertificateType {} 177 178 /** 179 * Query if the given scheme identified by its UUID is supported on 180 * this device. 181 * @param uuid The UUID of the crypto scheme. 182 */ isCryptoSchemeSupported(@onNull UUID uuid)183 public static final boolean isCryptoSchemeSupported(@NonNull UUID uuid) { 184 return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null, 185 SECURITY_LEVEL_UNKNOWN); 186 } 187 188 /** 189 * Query if the given scheme identified by its UUID is supported on 190 * this device, and whether the DRM plugin is able to handle the 191 * media container format specified by mimeType. 192 * @param uuid The UUID of the crypto scheme. 193 * @param mimeType The MIME type of the media container, e.g. "video/mp4" 194 * or "video/webm" 195 */ isCryptoSchemeSupported( @onNull UUID uuid, @NonNull String mimeType)196 public static final boolean isCryptoSchemeSupported( 197 @NonNull UUID uuid, @NonNull String mimeType) { 198 return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), 199 mimeType, SECURITY_LEVEL_UNKNOWN); 200 } 201 202 /** 203 * Query if the given scheme identified by its UUID is supported on 204 * this device, and whether the DRM plugin is able to handle the 205 * media container format specified by mimeType at the requested 206 * security level. 207 * 208 * @param uuid The UUID of the crypto scheme. 209 * @param mimeType The MIME type of the media container, e.g. "video/mp4" 210 * or "video/webm" 211 * @param securityLevel the security level requested 212 */ isCryptoSchemeSupported( @onNull UUID uuid, @NonNull String mimeType, @SecurityLevel int securityLevel)213 public static final boolean isCryptoSchemeSupported( 214 @NonNull UUID uuid, @NonNull String mimeType, @SecurityLevel int securityLevel) { 215 return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType, 216 securityLevel); 217 } 218 219 /** 220 * @return list of crypto schemes (as {@link UUID}s) for which 221 * {@link #isCryptoSchemeSupported(UUID)} returns true; each {@link UUID} 222 * can be used as input to create {@link MediaDrm} objects via {@link #MediaDrm(UUID)}. 223 */ getSupportedCryptoSchemes()224 public static final @NonNull List<UUID> getSupportedCryptoSchemes(){ 225 byte[] uuidBytes = getSupportedCryptoSchemesNative(); 226 return getUUIDsFromByteArray(uuidBytes); 227 } 228 getByteArrayFromUUID(@onNull UUID uuid)229 private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) { 230 long msb = uuid.getMostSignificantBits(); 231 long lsb = uuid.getLeastSignificantBits(); 232 233 byte[] uuidBytes = new byte[16]; 234 for (int i = 0; i < 8; ++i) { 235 uuidBytes[i] = (byte)(msb >>> (8 * (7 - i))); 236 uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i))); 237 } 238 239 return uuidBytes; 240 } 241 getUUIDFromByteArray(@onNull byte[] uuidBytes, int off)242 private static final UUID getUUIDFromByteArray(@NonNull byte[] uuidBytes, int off) { 243 long msb = 0; 244 long lsb = 0; 245 246 for (int i = 0; i < 8; ++i) { 247 msb = (msb << 8) | (0xffl & uuidBytes[off + i]); 248 lsb = (lsb << 8) | (0xffl & uuidBytes[off + i + 8]); 249 } 250 251 return new UUID(msb, lsb); 252 } 253 getUUIDsFromByteArray(@onNull byte[] uuidBytes)254 private static final List<UUID> getUUIDsFromByteArray(@NonNull byte[] uuidBytes) { 255 Set<UUID> uuids = new LinkedHashSet<>(); 256 for (int off = 0; off < uuidBytes.length; off+=16) { 257 uuids.add(getUUIDFromByteArray(uuidBytes, off)); 258 } 259 return new ArrayList<>(uuids); 260 } 261 getSupportedCryptoSchemesNative()262 private static final native byte[] getSupportedCryptoSchemesNative(); 263 isCryptoSchemeSupportedNative( @onNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel)264 private static final native boolean isCryptoSchemeSupportedNative( 265 @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel); 266 createHandler()267 private Handler createHandler() { 268 Looper looper; 269 Handler handler; 270 if ((looper = Looper.myLooper()) != null) { 271 handler = new Handler(looper); 272 } else if ((looper = Looper.getMainLooper()) != null) { 273 handler = new Handler(looper); 274 } else { 275 handler = null; 276 } 277 return handler; 278 } 279 280 /** 281 * Instantiate a MediaDrm object 282 * 283 * @param uuid The UUID of the crypto scheme. 284 * 285 * @throws UnsupportedSchemeException if the device does not support the 286 * specified scheme UUID 287 */ MediaDrm(@onNull UUID uuid)288 public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException { 289 /* Native setup requires a weak reference to our object. 290 * It's easier to create it here than in C++. 291 */ 292 mAppPackageName = ActivityThread.currentOpPackageName(); 293 native_setup(new WeakReference<MediaDrm>(this), 294 getByteArrayFromUUID(uuid), mAppPackageName); 295 296 mCloseGuard.open("release"); 297 } 298 299 /** 300 * Error codes that may be returned from {@link 301 * MediaDrmStateException#getErrorCode()} and {@link 302 * MediaCodec.CryptoException#getErrorCode()} 303 * <p> 304 * The description of each error code includes steps that may be taken to 305 * resolve the error condition. For some errors however, a recovery action 306 * cannot be predetermined. The description of those codes refers to a 307 * general strategy for handling the error condition programmatically, which 308 * is to try the following in listed order until successful: 309 * <ol> 310 * <li> retry the operation </li> 311 * <li> if the operation is related to a session, {@link 312 * #closeSession(byte[]) close} the session, {@link #openSession() open} a 313 * new session, and retry the operation </li> 314 * <li> {@link #close() close} the {@link MediaDrm} instance and any other 315 * related components such as the {@link MediaCodec codec} and retry 316 * playback, or </li> 317 * <li> try using a different configuration of the {@link MediaDrm} plugin, 318 * such as a different {@link #openSession(int) security level}. </li> 319 * </ol> 320 * <p> 321 * If the problem still persists after all the aforementioned steps, please 322 * report the failure to the {@link MediaDrm} plugin vendor along with the 323 * {@link LogMessage log messages} returned by {@link 324 * MediaDrm#getLogMessages()}, and a bugreport if possible. 325 */ 326 public final static class ErrorCodes { ErrorCodes()327 private ErrorCodes() {} 328 329 /** 330 * ERROR_UNKNOWN is used where no other defined error code is applicable 331 * to the current failure. 332 * <p> 333 * Please see the general error handling strategy for unexpected errors 334 * described in {@link ErrorCodes}. 335 */ 336 public static final int ERROR_UNKNOWN = 0; 337 338 /** 339 * The requested key was not found when trying to perform a decrypt 340 * operation. 341 * <p> 342 * The operation can be retried after adding the correct decryption key. 343 */ 344 public static final int ERROR_NO_KEY = 1; 345 346 /** 347 * The key used for decryption is no longer valid due to license term 348 * expiration. 349 * <p> 350 * The operation can be retried after updating the expired keys. 351 */ 352 public static final int ERROR_KEY_EXPIRED = 2; 353 354 /** 355 * A required crypto resource was not able to be allocated while 356 * attempting the requested operation. 357 * <p> 358 * The operation can be retried if the app is able to release resources. 359 */ 360 public static final int ERROR_RESOURCE_BUSY = 3; 361 362 /** 363 * The output protection levels supported by the device are not 364 * sufficient to meet the requirements set by the content owner in the 365 * license policy. 366 */ 367 public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; 368 369 /** 370 * Decryption was attempted on a session that is not opened, which could 371 * be due to a failure to open the session, closing the session 372 * prematurely, the session being reclaimed by the resource manager, or 373 * a non-existent session id. 374 */ 375 public static final int ERROR_SESSION_NOT_OPENED = 5; 376 377 /** 378 * An operation was attempted that could not be supported by the crypto 379 * system of the device in its current configuration. 380 * <p> 381 * This may occur when the license policy requires device security 382 * features that aren't supported by the device, or due to an internal 383 * error in the crypto system that prevents the specified security 384 * policy from being met. 385 */ 386 public static final int ERROR_UNSUPPORTED_OPERATION = 6; 387 388 /** 389 * The security level of the device is not sufficient to meet the 390 * requirements set by the content owner in the license policy. 391 */ 392 public static final int ERROR_INSUFFICIENT_SECURITY = 7; 393 394 /** 395 * The video frame being decrypted exceeds the size of the device's 396 * protected output buffers. 397 * <p> 398 * When encountering this error the app should try playing content 399 * of a lower resolution or skipping the problematic frame. 400 */ 401 public static final int ERROR_FRAME_TOO_LARGE = 8; 402 403 /** 404 * The session state has been invalidated. This can occur on devices 405 * that are not capable of retaining crypto session state across device 406 * suspend/resume. 407 * <p> 408 * The session must be closed and a new session opened to resume 409 * operation. 410 */ 411 public static final int ERROR_LOST_STATE = 9; 412 413 /** 414 * Certificate is malformed or is of the wrong type. 415 * <p> 416 * Ensure the certificate provided by the app or returned from the 417 * license server is valid. Check with the {@link MediaDrm} plugin 418 * vendor for the expected certificate format. 419 */ 420 public static final int ERROR_CERTIFICATE_MALFORMED = 10; 421 422 /** 423 * Certificate has not been set. 424 * <p> 425 * Ensure the certificate has been provided by the app. Check with the 426 * {@link MediaDrm} plugin vendor for the expected method to provide 427 * {@link MediaDrm} a certificate. 428 */ 429 public static final int ERROR_CERTIFICATE_MISSING = 11; 430 431 /** 432 * An error happened within the crypto library used by the drm plugin. 433 */ 434 public static final int ERROR_CRYPTO_LIBRARY = 12; 435 436 /** 437 * Unexpected error reported by the device OEM subsystem. 438 * <p> 439 * Please see the general error handling strategy for unexpected errors 440 * described in {@link ErrorCodes}. 441 */ 442 public static final int ERROR_GENERIC_OEM = 13; 443 444 /** 445 * Unexpected internal failure in {@link MediaDrm}/{@link MediaCrypto}. 446 * <p> 447 * Please see the general error handling strategy for unexpected errors 448 * described in {@link ErrorCodes}. 449 */ 450 public static final int ERROR_GENERIC_PLUGIN = 14; 451 452 /** 453 * The init data parameter passed to {@link MediaDrm#getKeyRequest} is 454 * empty or invalid. 455 * <p> 456 * Init data is typically obtained from {@link 457 * MediaExtractor#getPsshInfo()} or {@link 458 * MediaExtractor#getDrmInitData()}. Check with the {@link MediaDrm} 459 * plugin vendor for the expected init data format. 460 */ 461 public static final int ERROR_INIT_DATA = 15; 462 463 /** 464 * Either the key was not loaded from the license before attempting the 465 * operation, or the key ID parameter provided by the app is incorrect. 466 * <p> 467 * Ensure the proper keys are in the license, and check the key ID 468 * parameter provided by the app is correct. Check with the {@link 469 * MediaDrm} plugin vendor for the expected license format. 470 */ 471 public static final int ERROR_KEY_NOT_LOADED = 16; 472 473 /** 474 * The license response was empty, fields are missing or otherwise 475 * unable to be parsed or decrypted. 476 * <p> 477 * Check for mistakes such as empty or overwritten buffers. Otherwise, 478 * check with the {@link MediaDrm} plugin vendor for the expected 479 * license format. 480 */ 481 public static final int ERROR_LICENSE_PARSE = 17; 482 483 /** 484 * The operation (e.g. to renew or persist a license) is prohibited by 485 * the license policy. 486 * <p> 487 * Check the license policy configuration on the license server. 488 */ 489 public static final int ERROR_LICENSE_POLICY = 18; 490 491 /** 492 * Failed to generate a release request because a field in the offline 493 * license is empty or malformed. 494 * <p> 495 * The license can't be released on the server, but the app may remove 496 * the offline license explicitly using {@link 497 * MediaDrm#removeOfflineLicense}. 498 */ 499 public static final int ERROR_LICENSE_RELEASE = 19; 500 501 /** 502 * The license server detected an error in the license request. 503 * <p> 504 * Check for errors on the license server. 505 */ 506 public static final int ERROR_LICENSE_REQUEST_REJECTED = 20; 507 508 /** 509 * Failed to restore an offline license because a field in the offline 510 * license is empty or malformed. 511 * <p> 512 * Try requesting the license again if the device is online. 513 */ 514 public static final int ERROR_LICENSE_RESTORE = 21; 515 516 /** 517 * Offline license is in an invalid state for the attempted operation. 518 * <p> 519 * Check the sequence of API calls made that can affect offline license 520 * state. For example, this could happen when the app attempts to 521 * restore a license after it has been released. 522 */ 523 public static final int ERROR_LICENSE_STATE = 22; 524 525 /** 526 * Failure in the media framework. 527 * <p> 528 * Try releasing media resources (e.g. {@link MediaCodec}, {@link 529 * MediaDrm}), and restarting playback. 530 */ 531 public static final int ERROR_MEDIA_FRAMEWORK = 23; 532 533 /** 534 * Error loading the provisioned certificate. 535 * <p> 536 * Re-provisioning may resolve the problem; check with the {@link 537 * MediaDrm} plugin vendor for re-provisioning instructions. Otherwise, 538 * using a different security level may resolve the issue. 539 */ 540 public static final int ERROR_PROVISIONING_CERTIFICATE = 24; 541 542 /** 543 * Required steps were not performed before provisioning was attempted. 544 * <p> 545 * Ask the {@link MediaDrm} plugin vendor for situations where this 546 * error may occur. 547 */ 548 public static final int ERROR_PROVISIONING_CONFIG = 25; 549 550 /** 551 * The provisioning response was empty, fields are missing or otherwise 552 * unable to be parsed. 553 * <p> 554 * Check for mistakes such as empty or overwritten buffers. Otherwise, 555 * check with the {@link MediaDrm} plugin vendor for the expected 556 * provisioning response format. 557 */ 558 public static final int ERROR_PROVISIONING_PARSE = 26; 559 560 /** 561 * The provisioning server detected an error in the provisioning 562 * request. 563 * <p> 564 * Check for errors on the provisioning server. 565 */ 566 public static final int ERROR_PROVISIONING_REQUEST_REJECTED = 27; 567 568 /** 569 * Provisioning failed in a way that is likely to succeed on a 570 * subsequent attempt. 571 * <p> 572 * The app should retry the operation. 573 */ 574 public static final int ERROR_PROVISIONING_RETRY = 28; 575 576 /** 577 * This indicates that apps using MediaDrm sessions are 578 * temporarily exceeding the capacity of available crypto 579 * resources. 580 * <p> 581 * The app should retry the operation later. 582 */ 583 public static final int ERROR_RESOURCE_CONTENTION = 29; 584 585 /** 586 * Failed to generate a secure stop request because a field in the 587 * stored license is empty or malformed. 588 * <p> 589 * The secure stop can't be released on the server, but the app may 590 * remove it explicitly using {@link MediaDrm#removeSecureStop}. 591 */ 592 public static final int ERROR_SECURE_STOP_RELEASE = 30; 593 594 /** 595 * The plugin was unable to read data from the filesystem. 596 * <p> 597 * Please see the general error handling strategy for unexpected errors 598 * described in {@link ErrorCodes}. 599 */ 600 public static final int ERROR_STORAGE_READ = 31; 601 602 /** 603 * The plugin was unable to write data to the filesystem. 604 * <p> 605 * Please see the general error handling strategy for unexpected errors 606 * described in {@link ErrorCodes}. 607 */ 608 public static final int ERROR_STORAGE_WRITE = 32; 609 610 /** 611 * {@link MediaCodec#queueSecureInputBuffer} called with 0 subsamples. 612 * <p> 613 * Check the {@link MediaCodec.CryptoInfo} object passed to {@link 614 * MediaCodec#queueSecureInputBuffer}. 615 */ 616 public static final int ERROR_ZERO_SUBSAMPLES = 33; 617 618 } 619 620 /** @hide */ 621 @IntDef({ 622 ErrorCodes.ERROR_NO_KEY, 623 ErrorCodes.ERROR_KEY_EXPIRED, 624 ErrorCodes.ERROR_RESOURCE_BUSY, 625 ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION, 626 ErrorCodes.ERROR_SESSION_NOT_OPENED, 627 ErrorCodes.ERROR_UNSUPPORTED_OPERATION, 628 ErrorCodes.ERROR_INSUFFICIENT_SECURITY, 629 ErrorCodes.ERROR_FRAME_TOO_LARGE, 630 ErrorCodes.ERROR_LOST_STATE, 631 ErrorCodes.ERROR_CERTIFICATE_MALFORMED, 632 ErrorCodes.ERROR_CERTIFICATE_MISSING, 633 ErrorCodes.ERROR_CRYPTO_LIBRARY, 634 ErrorCodes.ERROR_GENERIC_OEM, 635 ErrorCodes.ERROR_GENERIC_PLUGIN, 636 ErrorCodes.ERROR_INIT_DATA, 637 ErrorCodes.ERROR_KEY_NOT_LOADED, 638 ErrorCodes.ERROR_LICENSE_PARSE, 639 ErrorCodes.ERROR_LICENSE_POLICY, 640 ErrorCodes.ERROR_LICENSE_RELEASE, 641 ErrorCodes.ERROR_LICENSE_REQUEST_REJECTED, 642 ErrorCodes.ERROR_LICENSE_RESTORE, 643 ErrorCodes.ERROR_LICENSE_STATE, 644 ErrorCodes.ERROR_MEDIA_FRAMEWORK, 645 ErrorCodes.ERROR_PROVISIONING_CERTIFICATE, 646 ErrorCodes.ERROR_PROVISIONING_CONFIG, 647 ErrorCodes.ERROR_PROVISIONING_PARSE, 648 ErrorCodes.ERROR_PROVISIONING_REQUEST_REJECTED, 649 ErrorCodes.ERROR_PROVISIONING_RETRY, 650 ErrorCodes.ERROR_SECURE_STOP_RELEASE, 651 ErrorCodes.ERROR_STORAGE_READ, 652 ErrorCodes.ERROR_STORAGE_WRITE, 653 ErrorCodes.ERROR_ZERO_SUBSAMPLES 654 }) 655 @Retention(RetentionPolicy.SOURCE) 656 public @interface MediaDrmErrorCode {} 657 658 /** 659 * Thrown when a general failure occurs during a MediaDrm operation. 660 * Extends {@link IllegalStateException} with the addition of an error 661 * code that may be useful in diagnosing the failure. 662 * <p> 663 * Please refer to {@link ErrorCodes} for the general error handling 664 * strategy and details about each possible return value from {@link 665 * MediaDrmStateException#getErrorCode()}. 666 */ 667 public static final class MediaDrmStateException extends java.lang.IllegalStateException { 668 private final int mErrorCode; 669 private final String mDiagnosticInfo; 670 671 /** 672 * @hide 673 */ MediaDrmStateException(int errorCode, @Nullable String detailMessage)674 public MediaDrmStateException(int errorCode, @Nullable String detailMessage) { 675 super(detailMessage); 676 mErrorCode = errorCode; 677 678 // TODO get this from DRM session 679 final String sign = errorCode < 0 ? "neg_" : ""; 680 mDiagnosticInfo = 681 "android.media.MediaDrm.error_" + sign + Math.abs(errorCode); 682 683 } 684 685 /** 686 * Returns error code associated with this {@link 687 * MediaDrmStateException}. 688 * <p> 689 * Please refer to {@link ErrorCodes} for the general error handling 690 * strategy and details about each possible return value. 691 * 692 * @return an error code defined in {@link MediaDrm.ErrorCodes}. 693 */ 694 @MediaDrmErrorCode 695 public int getErrorCode() { 696 return mErrorCode; 697 } 698 699 /** 700 * Returns true if the {@link MediaDrmStateException} is a transient 701 * issue, perhaps due to resource constraints, and that the operation 702 * (e.g. provisioning) may succeed on a subsequent attempt. 703 */ 704 public boolean isTransient() { 705 return mErrorCode == ErrorCodes.ERROR_PROVISIONING_RETRY 706 || mErrorCode == ErrorCodes.ERROR_RESOURCE_CONTENTION; 707 } 708 709 /** 710 * Retrieve a developer-readable diagnostic information string 711 * associated with the exception. Do not show this to end-users, 712 * since this string will not be localized or generally comprehensible 713 * to end-users. 714 */ 715 @NonNull 716 public String getDiagnosticInfo() { 717 return mDiagnosticInfo; 718 } 719 } 720 721 /** 722 * {@link SessionException} is a misnomer because it may occur in methods 723 * <b>without</b> a session context. 724 * <p> 725 * A {@link SessionException} is most likely to be thrown when an operation 726 * failed in a way that is likely to succeed on a subsequent attempt; call 727 * {@link #isTransient()} to determine whether the app should retry the 728 * failing operation. 729 */ 730 public static final class SessionException extends RuntimeException { 731 public SessionException(int errorCode, @Nullable String detailMessage) { 732 super(detailMessage); 733 mErrorCode = errorCode; 734 } 735 736 /** 737 * The SessionException has an unknown error code. 738 * @deprecated Unused. 739 */ 740 public static final int ERROR_UNKNOWN = 0; 741 742 /** 743 * This indicates that apps using MediaDrm sessions are 744 * temporarily exceeding the capacity of available crypto 745 * resources. The app should retry the operation later. 746 * 747 * @deprecated Please use {@link #isTransient()} instead of comparing 748 * the return value of {@link #getErrorCode()} against 749 * {@link SessionException#ERROR_RESOURCE_CONTENTION}. 750 */ 751 public static final int ERROR_RESOURCE_CONTENTION = 1; 752 753 /** @hide */ 754 @IntDef({ 755 ERROR_RESOURCE_CONTENTION, 756 }) 757 @Retention(RetentionPolicy.SOURCE) 758 public @interface SessionErrorCode {} 759 760 /** 761 * Retrieve the error code associated with the SessionException 762 * 763 * @deprecated Please use {@link #isTransient()} instead of comparing 764 * the return value of {@link #getErrorCode()} against 765 * {@link SessionException#ERROR_RESOURCE_CONTENTION}. 766 */ 767 @SessionErrorCode 768 public int getErrorCode() { 769 return mErrorCode; 770 } 771 772 /** 773 * Returns true if the {@link SessionException} is a transient 774 * issue, perhaps due to resource constraints, and that the operation 775 * (e.g. provisioning, generating requests) may succeed on a subsequent 776 * attempt. 777 */ 778 public boolean isTransient() { 779 return mErrorCode == ERROR_RESOURCE_CONTENTION; 780 } 781 782 private final int mErrorCode; 783 } 784 785 /** 786 * Register a callback to be invoked when a session expiration update 787 * occurs. The app's OnExpirationUpdateListener will be notified 788 * when the expiration time of the keys in the session have changed. 789 * @param listener the callback that will be run, or {@code null} to unregister the 790 * previously registered callback. 791 * @param handler the handler on which the listener should be invoked, or 792 * {@code null} if the listener should be invoked on the calling thread's looper. 793 */ 794 public void setOnExpirationUpdateListener( 795 @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) { 796 setListenerWithHandler(EXPIRATION_UPDATE, handler, listener, 797 this::createOnExpirationUpdateListener); 798 } 799 /** 800 * Register a callback to be invoked when a session expiration update 801 * occurs. 802 * 803 * @see #setOnExpirationUpdateListener(OnExpirationUpdateListener, Handler) 804 * 805 * @param executor the executor through which the listener should be invoked 806 * @param listener the callback that will be run. 807 */ 808 public void setOnExpirationUpdateListener( 809 @NonNull @CallbackExecutor Executor executor, 810 @NonNull OnExpirationUpdateListener listener) { 811 setListenerWithExecutor(EXPIRATION_UPDATE, executor, listener, 812 this::createOnExpirationUpdateListener); 813 } 814 815 /** 816 * Clear the {@link OnExpirationUpdateListener}. 817 */ 818 public void clearOnExpirationUpdateListener() { 819 clearGenericListener(EXPIRATION_UPDATE); 820 } 821 822 /** 823 * Interface definition for a callback to be invoked when a drm session 824 * expiration update occurs 825 */ 826 public interface OnExpirationUpdateListener 827 { 828 /** 829 * Called when a session expiration update occurs, to inform the app 830 * about the change in expiration time 831 * 832 * @param md the MediaDrm object on which the event occurred 833 * @param sessionId the DRM session ID on which the event occurred 834 * @param expirationTime the new expiration time for the keys in the session. 835 * The time is in milliseconds, relative to the Unix epoch. A time of 836 * 0 indicates that the keys never expire. 837 */ 838 void onExpirationUpdate( 839 @NonNull MediaDrm md, @NonNull byte[] sessionId, long expirationTime); 840 } 841 842 /** 843 * Register a callback to be invoked when the state of keys in a session 844 * change, e.g. when a license update occurs or when a license expires. 845 * 846 * @param listener the callback that will be run when key status changes, or 847 * {@code null} to unregister the previously registered callback. 848 * @param handler the handler on which the listener should be invoked, or 849 * null if the listener should be invoked on the calling thread's looper. 850 */ 851 public void setOnKeyStatusChangeListener( 852 @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) { 853 setListenerWithHandler(KEY_STATUS_CHANGE, handler, listener, 854 this::createOnKeyStatusChangeListener); 855 } 856 857 /** 858 * Register a callback to be invoked when the state of keys in a session 859 * change. 860 * 861 * @see #setOnKeyStatusChangeListener(OnKeyStatusChangeListener, Handler) 862 * 863 * @param listener the callback that will be run when key status changes. 864 * @param executor the executor on which the listener should be invoked. 865 */ 866 public void setOnKeyStatusChangeListener( 867 @NonNull @CallbackExecutor Executor executor, 868 @NonNull OnKeyStatusChangeListener listener) { 869 setListenerWithExecutor(KEY_STATUS_CHANGE, executor, listener, 870 this::createOnKeyStatusChangeListener); 871 } 872 873 /** 874 * Clear the {@link OnKeyStatusChangeListener}. 875 */ 876 public void clearOnKeyStatusChangeListener() { 877 clearGenericListener(KEY_STATUS_CHANGE); 878 } 879 880 /** 881 * Interface definition for a callback to be invoked when the keys in a drm 882 * session change states. 883 */ 884 public interface OnKeyStatusChangeListener 885 { 886 /** 887 * Called when the keys in a session change status, such as when the license 888 * is renewed or expires. 889 * 890 * @param md the MediaDrm object on which the event occurred 891 * @param sessionId the DRM session ID on which the event occurred 892 * @param keyInformation a list of {@link MediaDrm.KeyStatus} 893 * instances indicating the status for each key in the session 894 * @param hasNewUsableKey indicates if a key has been added that is usable, 895 * which may trigger an attempt to resume playback on the media stream 896 * if it is currently blocked waiting for a key. 897 */ 898 void onKeyStatusChange( 899 @NonNull MediaDrm md, @NonNull byte[] sessionId, 900 @NonNull List<KeyStatus> keyInformation, 901 boolean hasNewUsableKey); 902 } 903 904 /** 905 * Register a callback to be invoked when session state has been 906 * lost. This event can occur on devices that are not capable of 907 * retaining crypto session state across device suspend/resume 908 * cycles. When this event occurs, the session must be closed and 909 * a new session opened to resume operation. 910 * 911 * @param listener the callback that will be run, or {@code null} to unregister the 912 * previously registered callback. 913 * @param handler the handler on which the listener should be invoked, or 914 * {@code null} if the listener should be invoked on the calling thread's looper. 915 */ 916 public void setOnSessionLostStateListener( 917 @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) { 918 setListenerWithHandler(SESSION_LOST_STATE, handler, listener, 919 this::createOnSessionLostStateListener); 920 } 921 922 /** 923 * Register a callback to be invoked when session state has been 924 * lost. 925 * 926 * @see #setOnSessionLostStateListener(OnSessionLostStateListener, Handler) 927 * 928 * @param listener the callback that will be run. 929 * @param executor the executor on which the listener should be invoked. 930 */ 931 public void setOnSessionLostStateListener( 932 @NonNull @CallbackExecutor Executor executor, 933 @Nullable OnSessionLostStateListener listener) { 934 setListenerWithExecutor(SESSION_LOST_STATE, executor, listener, 935 this::createOnSessionLostStateListener); 936 } 937 938 /** 939 * Clear the {@link OnSessionLostStateListener}. 940 */ 941 public void clearOnSessionLostStateListener() { 942 clearGenericListener(SESSION_LOST_STATE); 943 } 944 945 /** 946 * Interface definition for a callback to be invoked when the 947 * session state has been lost and is now invalid 948 */ 949 public interface OnSessionLostStateListener 950 { 951 /** 952 * Called when session state has lost state, to inform the app 953 * about the condition so it can close the session and open a new 954 * one to resume operation. 955 * 956 * @param md the MediaDrm object on which the event occurred 957 * @param sessionId the DRM session ID on which the event occurred 958 */ 959 void onSessionLostState( 960 @NonNull MediaDrm md, @NonNull byte[] sessionId); 961 } 962 963 /** 964 * Defines the status of a key. 965 * A KeyStatus for each key in a session is provided to the 966 * {@link OnKeyStatusChangeListener#onKeyStatusChange} 967 * listener. 968 */ 969 public static final class KeyStatus { 970 private final byte[] mKeyId; 971 private final int mStatusCode; 972 973 /** 974 * The key is currently usable to decrypt media data 975 */ 976 public static final int STATUS_USABLE = 0; 977 978 /** 979 * The key is no longer usable to decrypt media data because its 980 * expiration time has passed. 981 */ 982 public static final int STATUS_EXPIRED = 1; 983 984 /** 985 * The key is not currently usable to decrypt media data because its 986 * output requirements cannot currently be met. 987 */ 988 public static final int STATUS_OUTPUT_NOT_ALLOWED = 2; 989 990 /** 991 * The status of the key is not yet known and is being determined. 992 * The status will be updated with the actual status when it has 993 * been determined. 994 */ 995 public static final int STATUS_PENDING = 3; 996 997 /** 998 * The key is not currently usable to decrypt media data because of an 999 * internal error in processing unrelated to input parameters. This error 1000 * is not actionable by an app. 1001 */ 1002 public static final int STATUS_INTERNAL_ERROR = 4; 1003 1004 /** 1005 * The key is not yet usable to decrypt media because the start 1006 * time is in the future. The key will become usable when 1007 * its start time is reached. 1008 */ 1009 public static final int STATUS_USABLE_IN_FUTURE = 5; 1010 1011 /** @hide */ 1012 @IntDef({ 1013 STATUS_USABLE, 1014 STATUS_EXPIRED, 1015 STATUS_OUTPUT_NOT_ALLOWED, 1016 STATUS_PENDING, 1017 STATUS_INTERNAL_ERROR, 1018 STATUS_USABLE_IN_FUTURE, 1019 }) 1020 @Retention(RetentionPolicy.SOURCE) 1021 public @interface KeyStatusCode {} 1022 1023 KeyStatus(@NonNull byte[] keyId, @KeyStatusCode int statusCode) { 1024 mKeyId = keyId; 1025 mStatusCode = statusCode; 1026 } 1027 1028 /** 1029 * Returns the status code for the key 1030 */ 1031 @KeyStatusCode 1032 public int getStatusCode() { return mStatusCode; } 1033 1034 /** 1035 * Returns the id for the key 1036 */ 1037 @NonNull 1038 public byte[] getKeyId() { return mKeyId; } 1039 } 1040 1041 /** 1042 * Register a callback to be invoked when an event occurs 1043 * 1044 * @see #setOnEventListener(OnEventListener, Handler) 1045 * 1046 * @param listener the callback that will be run. Use {@code null} to 1047 * stop receiving event callbacks. 1048 */ 1049 public void setOnEventListener(@Nullable OnEventListener listener) 1050 { 1051 setOnEventListener(listener, null); 1052 } 1053 1054 /** 1055 * Register a callback to be invoked when an event occurs 1056 * 1057 * @param listener the callback that will be run. Use {@code null} to 1058 * stop receiving event callbacks. 1059 * @param handler the handler on which the listener should be invoked, or 1060 * null if the listener should be invoked on the calling thread's looper. 1061 */ 1062 1063 public void setOnEventListener(@Nullable OnEventListener listener, @Nullable Handler handler) 1064 { 1065 setListenerWithHandler(DRM_EVENT, handler, listener, this::createOnEventListener); 1066 } 1067 1068 /** 1069 * Register a callback to be invoked when an event occurs 1070 * 1071 * @see #setOnEventListener(OnEventListener) 1072 * 1073 * @param executor the executor through which the listener should be invoked 1074 * @param listener the callback that will be run. 1075 */ 1076 public void setOnEventListener(@NonNull @CallbackExecutor Executor executor, 1077 @NonNull OnEventListener listener) { 1078 setListenerWithExecutor(DRM_EVENT, executor, listener, this::createOnEventListener); 1079 } 1080 1081 /** 1082 * Clear the {@link OnEventListener}. 1083 */ 1084 public void clearOnEventListener() { 1085 clearGenericListener(DRM_EVENT); 1086 } 1087 1088 /** 1089 * Interface definition for a callback to be invoked when a drm event 1090 * occurs 1091 */ 1092 public interface OnEventListener 1093 { 1094 /** 1095 * Called when an event occurs that requires the app to be notified 1096 * 1097 * @param md the MediaDrm object on which the event occurred 1098 * @param sessionId the DRM session ID on which the event occurred, 1099 * or {@code null} if there is no session ID associated with the event. 1100 * @param event indicates the event type 1101 * @param extra an secondary error code 1102 * @param data optional byte array of data that may be associated with the event 1103 */ 1104 void onEvent( 1105 @NonNull MediaDrm md, @Nullable byte[] sessionId, 1106 @DrmEvent int event, int extra, 1107 @Nullable byte[] data); 1108 } 1109 1110 /** 1111 * This event type indicates that the app needs to request a certificate from 1112 * the provisioning server. The request message data is obtained using 1113 * {@link #getProvisionRequest} 1114 * 1115 * @deprecated Handle provisioning via {@link android.media.NotProvisionedException} 1116 * instead. 1117 */ 1118 public static final int EVENT_PROVISION_REQUIRED = 1; 1119 1120 /** 1121 * This event type indicates that the app needs to request keys from a license 1122 * server. The request message data is obtained using {@link #getKeyRequest}. 1123 */ 1124 public static final int EVENT_KEY_REQUIRED = 2; 1125 1126 /** 1127 * This event type indicates that the licensed usage duration for keys in a session 1128 * has expired. The keys are no longer valid. 1129 * @deprecated Use {@link OnKeyStatusChangeListener#onKeyStatusChange} 1130 * and check for {@link MediaDrm.KeyStatus#STATUS_EXPIRED} in the {@link MediaDrm.KeyStatus} 1131 * instead. 1132 */ 1133 public static final int EVENT_KEY_EXPIRED = 3; 1134 1135 /** 1136 * This event may indicate some specific vendor-defined condition, see your 1137 * DRM provider documentation for details 1138 */ 1139 public static final int EVENT_VENDOR_DEFINED = 4; 1140 1141 /** 1142 * This event indicates that a session opened by the app has been reclaimed by the resource 1143 * manager. 1144 */ 1145 public static final int EVENT_SESSION_RECLAIMED = 5; 1146 1147 /** @hide */ 1148 @IntDef({ 1149 EVENT_PROVISION_REQUIRED, 1150 EVENT_KEY_REQUIRED, 1151 EVENT_KEY_EXPIRED, 1152 EVENT_VENDOR_DEFINED, 1153 EVENT_SESSION_RECLAIMED, 1154 }) 1155 @Retention(RetentionPolicy.SOURCE) 1156 public @interface DrmEvent {} 1157 1158 private static final int DRM_EVENT = 200; 1159 private static final int EXPIRATION_UPDATE = 201; 1160 private static final int KEY_STATUS_CHANGE = 202; 1161 private static final int SESSION_LOST_STATE = 203; 1162 1163 // Use ConcurrentMap to support concurrent read/write to listener settings. 1164 // ListenerWithExecutor is immutable so we shouldn't need further locks. 1165 private final Map<Integer, ListenerWithExecutor> mListenerMap = new ConcurrentHashMap<>(); 1166 1167 // called by old-style set*Listener APIs using Handlers; listener & handler are Nullable 1168 private <T> void setListenerWithHandler(int what, Handler handler, T listener, 1169 Function<T, Consumer<ListenerArgs>> converter) { 1170 if (listener == null) { 1171 clearGenericListener(what); 1172 } else { 1173 handler = handler == null ? createHandler() : handler; 1174 final HandlerExecutor executor = new HandlerExecutor(handler); 1175 setGenericListener(what, executor, listener, converter); 1176 } 1177 } 1178 1179 // called by new-style set*Listener APIs using Executors; listener & executor must be NonNull 1180 private <T> void setListenerWithExecutor(int what, Executor executor, T listener, 1181 Function<T, Consumer<ListenerArgs>> converter) { 1182 if (executor == null || listener == null) { 1183 final String errMsg = String.format("executor %s listener %s", executor, listener); 1184 throw new IllegalArgumentException(errMsg); 1185 } 1186 setGenericListener(what, executor, listener, converter); 1187 } 1188 1189 private <T> void setGenericListener(int what, Executor executor, T listener, 1190 Function<T, Consumer<ListenerArgs>> converter) { 1191 mListenerMap.put(what, new ListenerWithExecutor(executor, converter.apply(listener))); 1192 } 1193 1194 private void clearGenericListener(int what) { 1195 mListenerMap.remove(what); 1196 } 1197 1198 private Consumer<ListenerArgs> createOnEventListener(OnEventListener listener) { 1199 return args -> { 1200 byte[] sessionId = args.sessionId; 1201 if (sessionId.length == 0) { 1202 sessionId = null; 1203 } 1204 byte[] data = args.data; 1205 if (data != null && data.length == 0) { 1206 data = null; 1207 } 1208 1209 Log.i(TAG, "Drm event (" + args.arg1 + "," + args.arg2 + ")"); 1210 listener.onEvent(this, sessionId, args.arg1, args.arg2, data); 1211 }; 1212 } 1213 createOnKeyStatusChangeListener( OnKeyStatusChangeListener listener)1214 private Consumer<ListenerArgs> createOnKeyStatusChangeListener( 1215 OnKeyStatusChangeListener listener) { 1216 return args -> { 1217 byte[] sessionId = args.sessionId; 1218 if (sessionId.length > 0) { 1219 List<KeyStatus> keyStatusList = args.keyStatusList; 1220 boolean hasNewUsableKey = args.hasNewUsableKey; 1221 1222 Log.i(TAG, "Drm key status changed"); 1223 listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey); 1224 } 1225 }; 1226 } 1227 createOnExpirationUpdateListener( OnExpirationUpdateListener listener)1228 private Consumer<ListenerArgs> createOnExpirationUpdateListener( 1229 OnExpirationUpdateListener listener) { 1230 return args -> { 1231 byte[] sessionId = args.sessionId; 1232 if (sessionId.length > 0) { 1233 long expirationTime = args.expirationTime; 1234 1235 Log.i(TAG, "Drm key expiration update: " + expirationTime); 1236 listener.onExpirationUpdate(this, sessionId, expirationTime); 1237 } 1238 }; 1239 } 1240 createOnSessionLostStateListener( OnSessionLostStateListener listener)1241 private Consumer<ListenerArgs> createOnSessionLostStateListener( 1242 OnSessionLostStateListener listener) { 1243 return args -> { 1244 byte[] sessionId = args.sessionId; 1245 Log.i(TAG, "Drm session lost state event: "); 1246 listener.onSessionLostState(this, sessionId); 1247 }; 1248 } 1249 1250 private static class ListenerArgs { 1251 private final int arg1; 1252 private final int arg2; 1253 private final byte[] sessionId; 1254 private final byte[] data; 1255 private final long expirationTime; 1256 private final List<KeyStatus> keyStatusList; 1257 private final boolean hasNewUsableKey; 1258 1259 public ListenerArgs( 1260 int arg1, 1261 int arg2, 1262 byte[] sessionId, 1263 byte[] data, 1264 long expirationTime, 1265 List<KeyStatus> keyStatusList, 1266 boolean hasNewUsableKey) { 1267 this.arg1 = arg1; 1268 this.arg2 = arg2; 1269 this.sessionId = sessionId; 1270 this.data = data; 1271 this.expirationTime = expirationTime; 1272 this.keyStatusList = keyStatusList; 1273 this.hasNewUsableKey = hasNewUsableKey; 1274 } 1275 1276 } 1277 1278 private static class ListenerWithExecutor { 1279 private final Consumer<ListenerArgs> mConsumer; 1280 private final Executor mExecutor; 1281 1282 public ListenerWithExecutor(Executor executor, Consumer<ListenerArgs> consumer) { 1283 this.mExecutor = executor; 1284 this.mConsumer = consumer; 1285 } 1286 } 1287 1288 /** 1289 * Parse a list of KeyStatus objects from an event parcel 1290 */ 1291 @NonNull 1292 private List<KeyStatus> keyStatusListFromParcel(@NonNull Parcel parcel) { 1293 int nelems = parcel.readInt(); 1294 List<KeyStatus> keyStatusList = new ArrayList(nelems); 1295 while (nelems-- > 0) { 1296 byte[] keyId = parcel.createByteArray(); 1297 int keyStatusCode = parcel.readInt(); 1298 keyStatusList.add(new KeyStatus(keyId, keyStatusCode)); 1299 } 1300 return keyStatusList; 1301 } 1302 1303 /** 1304 * This method is called from native code when an event occurs. This method 1305 * just uses the EventHandler system to post the event back to the main app thread. 1306 * We use a weak reference to the original MediaPlayer object so that the native 1307 * code is safe from the object disappearing from underneath it. (This is 1308 * the cookie passed to native_setup().) 1309 */ 1310 private static void postEventFromNative(@NonNull Object mediadrm_ref, 1311 int what, int eventType, int extra, 1312 byte[] sessionId, byte[] data, long expirationTime, 1313 List<KeyStatus> keyStatusList, boolean hasNewUsableKey) 1314 { 1315 MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get(); 1316 if (md == null) { 1317 return; 1318 } 1319 switch (what) { 1320 case DRM_EVENT: 1321 case EXPIRATION_UPDATE: 1322 case KEY_STATUS_CHANGE: 1323 case SESSION_LOST_STATE: 1324 ListenerWithExecutor listener = md.mListenerMap.get(what); 1325 if (listener != null) { 1326 final Runnable command = () -> { 1327 if (md.mNativeContext == 0) { 1328 Log.w(TAG, "MediaDrm went away with unhandled events"); 1329 return; 1330 } 1331 ListenerArgs args = new ListenerArgs(eventType, extra, 1332 sessionId, data, expirationTime, 1333 keyStatusList, hasNewUsableKey); 1334 listener.mConsumer.accept(args); 1335 }; 1336 listener.mExecutor.execute(command); 1337 } 1338 break; 1339 default: 1340 Log.e(TAG, "Unknown message type " + what); 1341 break; 1342 } 1343 } 1344 1345 /** 1346 * Open a new session with the MediaDrm object. A session ID is returned. 1347 * By default, sessions are opened at the native security level of the device. 1348 * 1349 * @throws NotProvisionedException if provisioning is needed 1350 * @throws ResourceBusyException if required resources are in use 1351 */ 1352 @NonNull 1353 public byte[] openSession() throws NotProvisionedException, 1354 ResourceBusyException { 1355 return openSession(getMaxSecurityLevel()); 1356 } 1357 1358 /** 1359 * Open a new session at a requested security level. The security level 1360 * represents the robustness of the device's DRM implementation. By default, 1361 * sessions are opened at the native security level of the device. 1362 * Overriding the security level is necessary when the decrypted frames need 1363 * to be manipulated, such as for image compositing. The security level 1364 * parameter must be lower than the native level. Reducing the security 1365 * level will typically limit the content to lower resolutions, as 1366 * determined by the license policy. If the requested level is not 1367 * supported, the next lower supported security level will be set. The level 1368 * can be queried using {@link #getSecurityLevel}. A session 1369 * ID is returned. 1370 * 1371 * @param level the new security level 1372 * @throws NotProvisionedException if provisioning is needed 1373 * @throws ResourceBusyException if required resources are in use 1374 * @throws IllegalArgumentException if the requested security level is 1375 * higher than the native level or lower than the lowest supported level or 1376 * if the device does not support specifying the security level when opening 1377 * a session 1378 */ 1379 @NonNull 1380 public byte[] openSession(@SecurityLevel int level) throws 1381 NotProvisionedException, ResourceBusyException { 1382 byte[] sessionId = openSessionNative(level); 1383 mPlaybackComponentMap.put(ByteBuffer.wrap(sessionId), new PlaybackComponent(sessionId)); 1384 return sessionId; 1385 } 1386 1387 @NonNull 1388 private native byte[] openSessionNative(int level) throws 1389 NotProvisionedException, ResourceBusyException; 1390 1391 /** 1392 * Close a session on the MediaDrm object that was previously opened 1393 * with {@link #openSession}. 1394 */ 1395 public void closeSession(@NonNull byte[] sessionId) { 1396 closeSessionNative(sessionId); 1397 mPlaybackComponentMap.remove(ByteBuffer.wrap(sessionId)); 1398 } 1399 1400 private native void closeSessionNative(@NonNull byte[] sessionId); 1401 1402 private final Map<ByteBuffer, PlaybackComponent> mPlaybackComponentMap 1403 = new ConcurrentHashMap<>(); 1404 1405 /** 1406 * This key request type species that the keys will be for online use, they will 1407 * not be saved to the device for subsequent use when the device is not connected 1408 * to a network. 1409 */ 1410 public static final int KEY_TYPE_STREAMING = 1; 1411 1412 /** 1413 * This key request type specifies that the keys will be for offline use, they 1414 * will be saved to the device for use when the device is not connected to a network. 1415 */ 1416 public static final int KEY_TYPE_OFFLINE = 2; 1417 1418 /** 1419 * This key request type specifies that previously saved offline keys should be released. 1420 */ 1421 public static final int KEY_TYPE_RELEASE = 3; 1422 1423 /** @hide */ 1424 @IntDef({ 1425 KEY_TYPE_STREAMING, 1426 KEY_TYPE_OFFLINE, 1427 KEY_TYPE_RELEASE, 1428 }) 1429 @Retention(RetentionPolicy.SOURCE) 1430 public @interface KeyType {} 1431 1432 /** 1433 * Contains the opaque data an app uses to request keys from a license server. 1434 * These request types may or may not be generated by a given plugin. Refer 1435 * to plugin vendor documentation for more information. 1436 */ 1437 public static final class KeyRequest { 1438 private byte[] mData; 1439 private String mDefaultUrl; 1440 private int mRequestType; 1441 1442 /** 1443 * Key request type is initial license request. A license request 1444 * is necessary to load keys. 1445 */ 1446 public static final int REQUEST_TYPE_INITIAL = 0; 1447 1448 /** 1449 * Key request type is license renewal. A license request is 1450 * necessary to prevent the keys from expiring. 1451 */ 1452 public static final int REQUEST_TYPE_RENEWAL = 1; 1453 1454 /** 1455 * Key request type is license release 1456 */ 1457 public static final int REQUEST_TYPE_RELEASE = 2; 1458 1459 /** 1460 * Keys are already loaded and are available for use. No license request is necessary, and 1461 * no key request data is returned. 1462 */ 1463 public static final int REQUEST_TYPE_NONE = 3; 1464 1465 /** 1466 * Keys have been loaded but an additional license request is needed 1467 * to update their values. 1468 */ 1469 public static final int REQUEST_TYPE_UPDATE = 4; 1470 1471 /** @hide */ 1472 @IntDef({ 1473 REQUEST_TYPE_INITIAL, 1474 REQUEST_TYPE_RENEWAL, 1475 REQUEST_TYPE_RELEASE, 1476 REQUEST_TYPE_NONE, 1477 REQUEST_TYPE_UPDATE, 1478 }) 1479 @Retention(RetentionPolicy.SOURCE) 1480 public @interface RequestType {} 1481 1482 KeyRequest() {} 1483 1484 /** 1485 * Get the opaque message data 1486 */ 1487 @NonNull 1488 public byte[] getData() { 1489 if (mData == null) { 1490 // this should never happen as mData is initialized in 1491 // JNI after construction of the KeyRequest object. The check 1492 // is needed here to guarantee @NonNull annotation. 1493 throw new RuntimeException("KeyRequest is not initialized"); 1494 } 1495 return mData; 1496 } 1497 1498 /** 1499 * Get the default URL to use when sending the key request message to a 1500 * server, if known. The app may prefer to use a different license 1501 * server URL from other sources. 1502 * This method returns an empty string if the default URL is not known. 1503 */ 1504 @NonNull 1505 public String getDefaultUrl() { 1506 if (mDefaultUrl == null) { 1507 // this should never happen as mDefaultUrl is initialized in 1508 // JNI after construction of the KeyRequest object. The check 1509 // is needed here to guarantee @NonNull annotation. 1510 throw new RuntimeException("KeyRequest is not initialized"); 1511 } 1512 return mDefaultUrl; 1513 } 1514 1515 /** 1516 * Get the type of the request 1517 */ 1518 @RequestType 1519 public int getRequestType() { return mRequestType; } 1520 }; 1521 1522 /** 1523 * A key request/response exchange occurs between the app and a license server 1524 * to obtain or release keys used to decrypt encrypted content. 1525 * <p> 1526 * getKeyRequest() is used to obtain an opaque key request byte array that is 1527 * delivered to the license server. The opaque key request byte array is returned 1528 * in KeyRequest.data. The recommended URL to deliver the key request to is 1529 * returned in KeyRequest.defaultUrl. 1530 * <p> 1531 * After the app has received the key request response from the server, 1532 * it should deliver to the response to the MediaDrm instance using the method 1533 * {@link #provideKeyResponse}. 1534 * 1535 * @param scope may be a sessionId or a keySetId, depending on the specified keyType. 1536 * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, 1537 * scope should be set to the sessionId the keys will be provided to. When the keyType 1538 * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys 1539 * being released. Releasing keys from a device invalidates them for all sessions. 1540 * @param init container-specific data, its meaning is interpreted based on the 1541 * mime type provided in the mimeType parameter. It could contain, for example, 1542 * the content ID, key ID or other data obtained from the content metadata that is 1543 * required in generating the key request. May be null when keyType is 1544 * KEY_TYPE_RELEASE or if the request is a renewal, i.e. not the first key 1545 * request for the session. 1546 * @param mimeType identifies the mime type of the content. May be null if the 1547 * keyType is KEY_TYPE_RELEASE or if the request is a renewal, i.e. not the 1548 * first key request for the session. 1549 * @param keyType specifes the type of the request. The request may be to acquire 1550 * keys for streaming or offline content, or to release previously acquired 1551 * keys, which are identified by a keySetId. 1552 * @param optionalParameters are included in the key request message to 1553 * allow a client application to provide additional message parameters to the server. 1554 * This may be {@code null} if no additional parameters are to be sent. 1555 * @throws NotProvisionedException if reprovisioning is needed, due to a 1556 * problem with the certifcate 1557 */ 1558 @NonNull 1559 public KeyRequest getKeyRequest( 1560 @NonNull byte[] scope, @Nullable byte[] init, 1561 @Nullable String mimeType, @KeyType int keyType, 1562 @Nullable HashMap<String, String> optionalParameters) 1563 throws NotProvisionedException { 1564 HashMap<String, String> internalParams; 1565 if (optionalParameters == null) { 1566 internalParams = new HashMap<>(); 1567 } else { 1568 internalParams = new HashMap<>(optionalParameters); 1569 } 1570 byte[] rawBytes = getNewestAvailablePackageCertificateRawBytes(); 1571 byte[] hashBytes = null; 1572 if (rawBytes != null) { 1573 hashBytes = getDigestBytes(rawBytes, "SHA-256"); 1574 } 1575 if (hashBytes != null) { 1576 Base64.Encoder encoderB64 = Base64.getEncoder(); 1577 String hashBytesB64 = encoderB64.encodeToString(hashBytes); 1578 internalParams.put("package_certificate_hash_bytes", hashBytesB64); 1579 } 1580 return getKeyRequestNative(scope, init, mimeType, keyType, internalParams); 1581 } 1582 1583 @Nullable 1584 private byte[] getNewestAvailablePackageCertificateRawBytes() { 1585 Application application = ActivityThread.currentApplication(); 1586 if (application == null) { 1587 Log.w(TAG, "pkg cert: Application is null"); 1588 return null; 1589 } 1590 PackageManager pm = application.getPackageManager(); 1591 if (pm == null) { 1592 Log.w(TAG, "pkg cert: PackageManager is null"); 1593 return null; 1594 } 1595 PackageInfo packageInfo = null; 1596 try { 1597 packageInfo = pm.getPackageInfo(mAppPackageName, 1598 PackageManager.GET_SIGNING_CERTIFICATES); 1599 } catch (PackageManager.NameNotFoundException e) { 1600 Log.w(TAG, mAppPackageName, e); 1601 } 1602 if (packageInfo == null || packageInfo.signingInfo == null) { 1603 Log.w(TAG, "pkg cert: PackageInfo or SigningInfo is null"); 1604 return null; 1605 } 1606 Signature[] signers = packageInfo.signingInfo.getApkContentsSigners(); 1607 if (signers != null && signers.length == 1) { 1608 return signers[0].toByteArray(); 1609 } 1610 Log.w(TAG, "pkg cert: " + signers.length + " signers"); 1611 return null; 1612 } 1613 1614 @Nullable 1615 private static byte[] getDigestBytes(@NonNull byte[] rawBytes, @NonNull String algorithm) { 1616 try { 1617 MessageDigest messageDigest = MessageDigest.getInstance(algorithm); 1618 return messageDigest.digest(rawBytes); 1619 } catch (NoSuchAlgorithmException e) { 1620 Log.w(TAG, algorithm, e); 1621 } 1622 return null; 1623 } 1624 1625 @NonNull 1626 private native KeyRequest getKeyRequestNative( 1627 @NonNull byte[] scope, @Nullable byte[] init, 1628 @Nullable String mimeType, @KeyType int keyType, 1629 @Nullable HashMap<String, String> optionalParameters) 1630 throws NotProvisionedException; 1631 1632 /** 1633 * A key response is received from the license server by the app, then it is 1634 * provided to the MediaDrm instance using provideKeyResponse. When the 1635 * response is for an offline key request, a keySetId is returned that can be 1636 * used to later restore the keys to a new session with the method 1637 * {@link #restoreKeys}. 1638 * When the response is for a streaming or release request, an empty byte array 1639 * is returned. 1640 * 1641 * @param scope may be a sessionId or keySetId depending on the type of the 1642 * response. Scope should be set to the sessionId when the response is for either 1643 * streaming or offline key requests. Scope should be set to the keySetId when 1644 * the response is for a release request. 1645 * @param response the byte array response from the server 1646 * @return If the response is for an offline request, the keySetId for the offline 1647 * keys will be returned. If the response is for a streaming or release request 1648 * an empty byte array will be returned. 1649 * 1650 * @throws NotProvisionedException if the response indicates that 1651 * reprovisioning is required 1652 * @throws DeniedByServerException if the response indicates that the 1653 * server rejected the request 1654 */ 1655 @Nullable 1656 public native byte[] provideKeyResponse( 1657 @NonNull byte[] scope, @NonNull byte[] response) 1658 throws NotProvisionedException, DeniedByServerException; 1659 1660 1661 /** 1662 * Restore persisted offline keys into a new session. keySetId identifies the 1663 * keys to load, obtained from a prior call to {@link #provideKeyResponse}. 1664 * 1665 * @param sessionId the session ID for the DRM session 1666 * @param keySetId identifies the saved key set to restore 1667 */ 1668 public native void restoreKeys(@NonNull byte[] sessionId, @NonNull byte[] keySetId); 1669 1670 /** 1671 * Remove the current keys from a session. 1672 * 1673 * @param sessionId the session ID for the DRM session 1674 */ 1675 public native void removeKeys(@NonNull byte[] sessionId); 1676 1677 /** 1678 * Request an informative description of the key status for the session. The status is 1679 * in the form of {name, value} pairs. Since DRM license policies vary by vendor, 1680 * the specific status field names are determined by each DRM vendor. Refer to your 1681 * DRM provider documentation for definitions of the field names for a particular 1682 * DRM plugin. 1683 * 1684 * @param sessionId the session ID for the DRM session 1685 */ 1686 @NonNull 1687 public native HashMap<String, String> queryKeyStatus(@NonNull byte[] sessionId); 1688 1689 /** 1690 * Contains the opaque data an app uses to request a certificate from a provisioning 1691 * server 1692 */ 1693 public static final class ProvisionRequest { 1694 ProvisionRequest() {} 1695 1696 /** 1697 * Get the opaque message data 1698 */ 1699 @NonNull 1700 public byte[] getData() { 1701 if (mData == null) { 1702 // this should never happen as mData is initialized in 1703 // JNI after construction of the KeyRequest object. The check 1704 // is needed here to guarantee @NonNull annotation. 1705 throw new RuntimeException("ProvisionRequest is not initialized"); 1706 } 1707 return mData; 1708 } 1709 1710 /** 1711 * Get the default URL to use when sending the provision request 1712 * message to a server, if known. The app may prefer to use a different 1713 * provisioning server URL obtained from other sources. 1714 * This method returns an empty string if the default URL is not known. 1715 */ 1716 @NonNull 1717 public String getDefaultUrl() { 1718 if (mDefaultUrl == null) { 1719 // this should never happen as mDefaultUrl is initialized in 1720 // JNI after construction of the ProvisionRequest object. The check 1721 // is needed here to guarantee @NonNull annotation. 1722 throw new RuntimeException("ProvisionRequest is not initialized"); 1723 } 1724 return mDefaultUrl; 1725 } 1726 1727 private byte[] mData; 1728 private String mDefaultUrl; 1729 } 1730 1731 /** 1732 * A provision request/response exchange occurs between the app and a provisioning 1733 * server to retrieve a device certificate. If provisionining is required, the 1734 * EVENT_PROVISION_REQUIRED event will be sent to the event handler. 1735 * getProvisionRequest is used to obtain the opaque provision request byte array that 1736 * should be delivered to the provisioning server. The provision request byte array 1737 * is returned in ProvisionRequest.data. The recommended URL to deliver the provision 1738 * request to is returned in ProvisionRequest.defaultUrl. 1739 */ 1740 @NonNull 1741 public ProvisionRequest getProvisionRequest() { 1742 return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, ""); 1743 } 1744 1745 @NonNull 1746 private native ProvisionRequest getProvisionRequestNative(int certType, 1747 @NonNull String certAuthority); 1748 1749 /** 1750 * After a provision response is received by the app, it is provided to the 1751 * MediaDrm instance using this method. 1752 * 1753 * @param response the opaque provisioning response byte array to provide to the 1754 * MediaDrm instance. 1755 * 1756 * @throws DeniedByServerException if the response indicates that the 1757 * server rejected the request 1758 */ 1759 public void provideProvisionResponse(@NonNull byte[] response) 1760 throws DeniedByServerException { 1761 provideProvisionResponseNative(response); 1762 } 1763 1764 @NonNull 1765 private native Certificate provideProvisionResponseNative(@NonNull byte[] response) 1766 throws DeniedByServerException; 1767 1768 /** 1769 * The keys in an offline license allow protected content to be played even 1770 * if the device is not connected to a network. Offline licenses are stored 1771 * on the device after a key request/response exchange when the key request 1772 * KeyType is OFFLINE. Normally each app is responsible for keeping track of 1773 * the keySetIds it has created. If an app loses the keySetId for any stored 1774 * licenses that it created, however, it must be able to recover the stored 1775 * keySetIds so those licenses can be removed when they expire or when the 1776 * app is uninstalled. 1777 * <p> 1778 * This method returns a list of the keySetIds for all offline licenses. 1779 * The offline license keySetId may be used to query the status of an 1780 * offline license with {@link #getOfflineLicenseState} or remove it with 1781 * {@link #removeOfflineLicense}. 1782 * 1783 * @return a list of offline license keySetIds 1784 */ 1785 @NonNull 1786 public native List<byte[]> getOfflineLicenseKeySetIds(); 1787 1788 /** 1789 * Normally offline licenses are released using a key request/response 1790 * exchange using {@link #getKeyRequest} where the key type is 1791 * KEY_TYPE_RELEASE, followed by {@link #provideKeyResponse}. This allows 1792 * the server to cryptographically confirm that the license has been removed 1793 * and then adjust the count of offline licenses allocated to the device. 1794 * <p> 1795 * In some exceptional situations it may be necessary to directly remove 1796 * offline licenses without notifying the server, which may be performed 1797 * using this method. 1798 * 1799 * @param keySetId the id of the offline license to remove 1800 * @throws IllegalArgumentException if the keySetId does not refer to an 1801 * offline license. 1802 */ 1803 public native void removeOfflineLicense(@NonNull byte[] keySetId); 1804 1805 /** 1806 * Offline license state is unknown, an error occurred while trying 1807 * to access it. 1808 */ 1809 public static final int OFFLINE_LICENSE_STATE_UNKNOWN = 0; 1810 1811 /** 1812 * Offline license is usable, the keys may be used for decryption. 1813 */ 1814 public static final int OFFLINE_LICENSE_STATE_USABLE = 1; 1815 1816 /** 1817 * Offline license is released, the keys have been marked for 1818 * release using {@link #getKeyRequest} with KEY_TYPE_RELEASE but 1819 * the key response has not been received. 1820 */ 1821 public static final int OFFLINE_LICENSE_STATE_RELEASED = 2; 1822 1823 /** @hide */ 1824 @IntDef({ 1825 OFFLINE_LICENSE_STATE_UNKNOWN, 1826 OFFLINE_LICENSE_STATE_USABLE, 1827 OFFLINE_LICENSE_STATE_RELEASED, 1828 }) 1829 @Retention(RetentionPolicy.SOURCE) 1830 public @interface OfflineLicenseState {} 1831 1832 /** 1833 * Request the state of an offline license. An offline license may be usable 1834 * or inactive. The keys in a usable offline license are available for 1835 * decryption. When the offline license state is inactive, the keys have 1836 * been marked for release using {@link #getKeyRequest} with 1837 * KEY_TYPE_RELEASE but the key response has not been received. The keys in 1838 * an inactive offline license are not usable for decryption. 1839 * 1840 * @param keySetId selects the offline license 1841 * @return the offline license state 1842 * @throws IllegalArgumentException if the keySetId does not refer to an 1843 * offline license. 1844 */ 1845 @OfflineLicenseState 1846 public native int getOfflineLicenseState(@NonNull byte[] keySetId); 1847 1848 /** 1849 * Secure stops are a way to enforce limits on the number of concurrent 1850 * streams per subscriber across devices. They provide secure monitoring of 1851 * the lifetime of content decryption keys in MediaDrm sessions. 1852 * <p> 1853 * A secure stop is written to secure persistent memory when keys are loaded 1854 * into a MediaDrm session. The secure stop state indicates that the keys 1855 * are available for use. When playback completes and the keys are removed 1856 * or the session is destroyed, the secure stop state is updated to indicate 1857 * that keys are no longer usable. 1858 * <p> 1859 * After playback, the app can query the secure stop and send it in a 1860 * message to the license server confirming that the keys are no longer 1861 * active. The license server returns a secure stop release response 1862 * message to the app which then deletes the secure stop from persistent 1863 * memory using {@link #releaseSecureStops}. 1864 * <p> 1865 * Each secure stop has a unique ID that can be used to identify it during 1866 * enumeration, access and removal. 1867 * @return a list of all secure stops from secure persistent memory 1868 */ 1869 @NonNull 1870 public native List<byte[]> getSecureStops(); 1871 1872 /** 1873 * Return a list of all secure stop IDs currently in persistent memory. 1874 * The secure stop ID can be used to access or remove the corresponding 1875 * secure stop. 1876 * 1877 * @return a list of secure stop IDs 1878 */ 1879 @NonNull 1880 public native List<byte[]> getSecureStopIds(); 1881 1882 /** 1883 * Access a specific secure stop given its secure stop ID. 1884 * Each secure stop has a unique ID. 1885 * 1886 * @param ssid the ID of the secure stop to return 1887 * @return the secure stop identified by ssid 1888 */ 1889 @NonNull 1890 public native byte[] getSecureStop(@NonNull byte[] ssid); 1891 1892 /** 1893 * Process the secure stop server response message ssRelease. After 1894 * authenticating the message, remove the secure stops identified in the 1895 * response. 1896 * 1897 * @param ssRelease the server response indicating which secure stops to release 1898 */ 1899 public native void releaseSecureStops(@NonNull byte[] ssRelease); 1900 1901 /** 1902 * Remove a specific secure stop without requiring a secure stop release message 1903 * from the license server. 1904 * @param ssid the ID of the secure stop to remove 1905 */ 1906 public native void removeSecureStop(@NonNull byte[] ssid); 1907 1908 /** 1909 * Remove all secure stops without requiring a secure stop release message from 1910 * the license server. 1911 * 1912 * This method was added in API 28. In API versions 18 through 27, 1913 * {@link #releaseAllSecureStops} should be called instead. There is no need to 1914 * do anything for API versions prior to 18. 1915 */ 1916 public native void removeAllSecureStops(); 1917 1918 /** 1919 * Remove all secure stops without requiring a secure stop release message from 1920 * the license server. 1921 * 1922 * @deprecated Remove all secure stops using {@link #removeAllSecureStops} instead. 1923 */ 1924 public void releaseAllSecureStops() { 1925 removeAllSecureStops();; 1926 } 1927 1928 /** 1929 * @deprecated Not of any use for application development; 1930 * please note that the related integer constants remain supported: 1931 * {@link #HDCP_LEVEL_UNKNOWN}, 1932 * {@link #HDCP_NONE}, 1933 * {@link #HDCP_V1}, 1934 * {@link #HDCP_V2}, 1935 * {@link #HDCP_V2_1}, 1936 * {@link #HDCP_V2_2}, 1937 * {@link #HDCP_V2_3} 1938 */ 1939 @Deprecated 1940 @Retention(RetentionPolicy.SOURCE) 1941 @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2, 1942 HDCP_V2_1, HDCP_V2_2, HDCP_V2_3, HDCP_NO_DIGITAL_OUTPUT}) 1943 public @interface HdcpLevel {} 1944 1945 1946 /** 1947 * The DRM plugin did not report an HDCP level, or an error 1948 * occurred accessing it 1949 */ 1950 public static final int HDCP_LEVEL_UNKNOWN = 0; 1951 1952 /** 1953 * HDCP is not supported on this device, content is unprotected 1954 */ 1955 public static final int HDCP_NONE = 1; 1956 1957 /** 1958 * HDCP version 1.0 1959 */ 1960 public static final int HDCP_V1 = 2; 1961 1962 /** 1963 * HDCP version 2.0 Type 1. 1964 */ 1965 public static final int HDCP_V2 = 3; 1966 1967 /** 1968 * HDCP version 2.1 Type 1. 1969 */ 1970 public static final int HDCP_V2_1 = 4; 1971 1972 /** 1973 * HDCP version 2.2 Type 1. 1974 */ 1975 public static final int HDCP_V2_2 = 5; 1976 1977 /** 1978 * HDCP version 2.3 Type 1. 1979 */ 1980 public static final int HDCP_V2_3 = 6; 1981 1982 /** 1983 * No digital output, implicitly secure 1984 */ 1985 public static final int HDCP_NO_DIGITAL_OUTPUT = Integer.MAX_VALUE; 1986 1987 /** 1988 * Return the HDCP level negotiated with downstream receivers the 1989 * device is connected to. If multiple HDCP-capable displays are 1990 * simultaneously connected to separate interfaces, this method 1991 * returns the lowest negotiated level of all interfaces. 1992 * <p> 1993 * This method should only be used for informational purposes, not for 1994 * enforcing compliance with HDCP requirements. Trusted enforcement of 1995 * HDCP policies must be handled by the DRM system. 1996 * <p> 1997 * @return the connected HDCP level 1998 */ 1999 @HdcpLevel 2000 public native int getConnectedHdcpLevel(); 2001 2002 /** 2003 * Return the maximum supported HDCP level. The maximum HDCP level is a 2004 * constant for a given device, it does not depend on downstream receivers 2005 * that may be connected. If multiple HDCP-capable interfaces are present, 2006 * it indicates the highest of the maximum HDCP levels of all interfaces. 2007 * <p> 2008 * @return the maximum supported HDCP level 2009 */ 2010 @HdcpLevel 2011 public native int getMaxHdcpLevel(); 2012 2013 /** 2014 * Return the number of MediaDrm sessions that are currently opened 2015 * simultaneously among all MediaDrm instances for the active DRM scheme. 2016 * @return the number of open sessions. 2017 */ 2018 public native int getOpenSessionCount(); 2019 2020 /** 2021 * Return the maximum number of MediaDrm sessions that may be opened 2022 * simultaneosly among all MediaDrm instances for the active DRM 2023 * scheme. The maximum number of sessions is not affected by any 2024 * sessions that may have already been opened. 2025 * @return maximum sessions. 2026 */ 2027 public native int getMaxSessionCount(); 2028 2029 /** 2030 * Security level indicates the robustness of the device's DRM 2031 * implementation. 2032 * 2033 * @deprecated Not of any use for application development; 2034 * please note that the related integer constants remain supported: 2035 * {@link #SECURITY_LEVEL_UNKNOWN}, 2036 * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}, 2037 * {@link #SECURITY_LEVEL_SW_SECURE_DECODE}, 2038 * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO}, 2039 * {@link #SECURITY_LEVEL_HW_SECURE_DECODE}, 2040 * {@link #SECURITY_LEVEL_HW_SECURE_ALL} 2041 */ 2042 @Deprecated 2043 @Retention(RetentionPolicy.SOURCE) 2044 @IntDef({SECURITY_LEVEL_UNKNOWN, SECURITY_LEVEL_SW_SECURE_CRYPTO, 2045 SECURITY_LEVEL_SW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_CRYPTO, 2046 SECURITY_LEVEL_HW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_ALL}) 2047 public @interface SecurityLevel {} 2048 2049 /** 2050 * The DRM plugin did not report a security level, or an error occurred 2051 * accessing it 2052 */ 2053 public static final int SECURITY_LEVEL_UNKNOWN = 0; 2054 2055 /** 2056 * DRM key management uses software-based whitebox crypto. 2057 */ 2058 public static final int SECURITY_LEVEL_SW_SECURE_CRYPTO = 1; 2059 2060 /** 2061 * DRM key management and decoding use software-based whitebox crypto. 2062 */ 2063 public static final int SECURITY_LEVEL_SW_SECURE_DECODE = 2; 2064 2065 /** 2066 * DRM key management and crypto operations are performed within a hardware 2067 * backed trusted execution environment. 2068 */ 2069 public static final int SECURITY_LEVEL_HW_SECURE_CRYPTO = 3; 2070 2071 /** 2072 * DRM key management, crypto operations and decoding of content are 2073 * performed within a hardware backed trusted execution environment. 2074 */ 2075 public static final int SECURITY_LEVEL_HW_SECURE_DECODE = 4; 2076 2077 /** 2078 * DRM key management, crypto operations, decoding of content and all 2079 * handling of the media (compressed and uncompressed) is handled within a 2080 * hardware backed trusted execution environment. 2081 */ 2082 public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5; 2083 2084 /** 2085 * Indicates that the maximum security level supported by the device should 2086 * be used when opening a session. This is the default security level 2087 * selected when a session is opened. 2088 * @hide 2089 */ 2090 public static final int SECURITY_LEVEL_MAX = 6; 2091 2092 /** 2093 * Returns a value that may be passed as a parameter to {@link #openSession(int)} 2094 * requesting that the session be opened at the maximum security level of 2095 * the device. 2096 */ 2097 public static final int getMaxSecurityLevel() { 2098 return SECURITY_LEVEL_MAX; 2099 } 2100 2101 /** 2102 * Return the current security level of a session. A session has an initial 2103 * security level determined by the robustness of the DRM system's 2104 * implementation on the device. The security level may be changed at the 2105 * time a session is opened using {@link #openSession}. 2106 * @param sessionId the session to query. 2107 * <p> 2108 * @return the security level of the session 2109 */ 2110 @SecurityLevel 2111 public native int getSecurityLevel(@NonNull byte[] sessionId); 2112 2113 /** 2114 * String property name: identifies the maker of the DRM plugin 2115 */ 2116 public static final String PROPERTY_VENDOR = "vendor"; 2117 2118 /** 2119 * String property name: identifies the version of the DRM plugin 2120 */ 2121 public static final String PROPERTY_VERSION = "version"; 2122 2123 /** 2124 * String property name: describes the DRM plugin 2125 */ 2126 public static final String PROPERTY_DESCRIPTION = "description"; 2127 2128 /** 2129 * String property name: a comma-separated list of cipher and mac algorithms 2130 * supported by CryptoSession. The list may be empty if the DRM 2131 * plugin does not support CryptoSession operations. 2132 */ 2133 public static final String PROPERTY_ALGORITHMS = "algorithms"; 2134 2135 /** @hide */ 2136 @StringDef(prefix = { "PROPERTY_" }, value = { 2137 PROPERTY_VENDOR, 2138 PROPERTY_VERSION, 2139 PROPERTY_DESCRIPTION, 2140 PROPERTY_ALGORITHMS, 2141 }) 2142 @Retention(RetentionPolicy.SOURCE) 2143 public @interface StringProperty {} 2144 2145 /** 2146 * Read a MediaDrm String property value, given the property name string. 2147 * <p> 2148 * Standard fields names are: 2149 * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION}, 2150 * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS} 2151 */ 2152 @NonNull 2153 public native String getPropertyString(@NonNull String propertyName); 2154 2155 /** 2156 * Set a MediaDrm String property value, given the property name string 2157 * and new value for the property. 2158 */ 2159 public native void setPropertyString(@NonNull String propertyName, 2160 @NonNull String value); 2161 2162 /** 2163 * Byte array property name: the device unique identifier is established during 2164 * device provisioning and provides a means of uniquely identifying each device. 2165 */ 2166 public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId"; 2167 2168 /** @hide */ 2169 @StringDef(prefix = { "PROPERTY_" }, value = { 2170 PROPERTY_DEVICE_UNIQUE_ID, 2171 }) 2172 @Retention(RetentionPolicy.SOURCE) 2173 public @interface ArrayProperty {} 2174 2175 /** 2176 * Read a MediaDrm byte array property value, given the property name string. 2177 * <p> 2178 * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID} 2179 */ 2180 @NonNull 2181 public native byte[] getPropertyByteArray(String propertyName); 2182 2183 /** 2184 * Set a MediaDrm byte array property value, given the property name string 2185 * and new value for the property. 2186 */ 2187 public native void setPropertyByteArray( 2188 @NonNull String propertyName, @NonNull byte[] value); 2189 2190 private static final native void setCipherAlgorithmNative( 2191 @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm); 2192 2193 private static final native void setMacAlgorithmNative( 2194 @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm); 2195 2196 @NonNull 2197 private static final native byte[] encryptNative( 2198 @NonNull MediaDrm drm, @NonNull byte[] sessionId, 2199 @NonNull byte[] keyId, @NonNull byte[] input, @NonNull byte[] iv); 2200 2201 @NonNull 2202 private static final native byte[] decryptNative( 2203 @NonNull MediaDrm drm, @NonNull byte[] sessionId, 2204 @NonNull byte[] keyId, @NonNull byte[] input, @NonNull byte[] iv); 2205 2206 @NonNull 2207 private static final native byte[] signNative( 2208 @NonNull MediaDrm drm, @NonNull byte[] sessionId, 2209 @NonNull byte[] keyId, @NonNull byte[] message); 2210 2211 private static final native boolean verifyNative( 2212 @NonNull MediaDrm drm, @NonNull byte[] sessionId, 2213 @NonNull byte[] keyId, @NonNull byte[] message, @NonNull byte[] signature); 2214 2215 /** 2216 * Return Metrics data about the current MediaDrm instance. 2217 * 2218 * @return a {@link PersistableBundle} containing the set of attributes and values 2219 * available for this instance of MediaDrm. 2220 * The attributes are described in {@link MetricsConstants}. 2221 * 2222 * Additional vendor-specific fields may also be present in 2223 * the return value. 2224 */ 2225 public PersistableBundle getMetrics() { 2226 PersistableBundle bundle = getMetricsNative(); 2227 return bundle; 2228 } 2229 2230 private native PersistableBundle getMetricsNative(); 2231 2232 /** 2233 * In addition to supporting decryption of DASH Common Encrypted Media, the 2234 * MediaDrm APIs provide the ability to securely deliver session keys from 2235 * an operator's session key server to a client device, based on the factory-installed 2236 * root of trust, and then perform encrypt, decrypt, sign and verify operations 2237 * with the session key on arbitrary user data. 2238 * <p> 2239 * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods 2240 * based on the established session keys. These keys are exchanged using the 2241 * getKeyRequest/provideKeyResponse methods. 2242 * <p> 2243 * Applications of this capability could include securing various types of 2244 * purchased or private content, such as applications, books and other media, 2245 * photos or media delivery protocols. 2246 * <p> 2247 * Operators can create session key servers that are functionally similar to a 2248 * license key server, except that instead of receiving license key requests and 2249 * providing encrypted content keys which are used specifically to decrypt A/V media 2250 * content, the session key server receives session key requests and provides 2251 * encrypted session keys which can be used for general purpose crypto operations. 2252 * <p> 2253 * A CryptoSession is obtained using {@link #getCryptoSession} 2254 */ 2255 public final class CryptoSession { 2256 private byte[] mSessionId; 2257 2258 CryptoSession(@NonNull byte[] sessionId, 2259 @NonNull String cipherAlgorithm, 2260 @NonNull String macAlgorithm) 2261 { 2262 mSessionId = sessionId; 2263 setCipherAlgorithmNative(MediaDrm.this, sessionId, cipherAlgorithm); 2264 setMacAlgorithmNative(MediaDrm.this, sessionId, macAlgorithm); 2265 } 2266 2267 /** 2268 * Encrypt data using the CryptoSession's cipher algorithm 2269 * 2270 * @param keyid specifies which key to use 2271 * @param input the data to encrypt 2272 * @param iv the initialization vector to use for the cipher 2273 */ 2274 @NonNull 2275 public byte[] encrypt( 2276 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) { 2277 return encryptNative(MediaDrm.this, mSessionId, keyid, input, iv); 2278 } 2279 2280 /** 2281 * Decrypt data using the CryptoSessions's cipher algorithm 2282 * 2283 * @param keyid specifies which key to use 2284 * @param input the data to encrypt 2285 * @param iv the initialization vector to use for the cipher 2286 */ 2287 @NonNull 2288 public byte[] decrypt( 2289 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) { 2290 return decryptNative(MediaDrm.this, mSessionId, keyid, input, iv); 2291 } 2292 2293 /** 2294 * Sign data using the CryptoSessions's mac algorithm. 2295 * 2296 * @param keyid specifies which key to use 2297 * @param message the data for which a signature is to be computed 2298 */ 2299 @NonNull 2300 public byte[] sign(@NonNull byte[] keyid, @NonNull byte[] message) { 2301 return signNative(MediaDrm.this, mSessionId, keyid, message); 2302 } 2303 2304 /** 2305 * Verify a signature using the CryptoSessions's mac algorithm. Return true 2306 * if the signatures match, false if they do no. 2307 * 2308 * @param keyid specifies which key to use 2309 * @param message the data to verify 2310 * @param signature the reference signature which will be compared with the 2311 * computed signature 2312 */ 2313 public boolean verify( 2314 @NonNull byte[] keyid, @NonNull byte[] message, @NonNull byte[] signature) { 2315 return verifyNative(MediaDrm.this, mSessionId, keyid, message, signature); 2316 } 2317 }; 2318 2319 /** 2320 * Obtain a CryptoSession object which can be used to encrypt, decrypt, 2321 * sign and verify messages or data using the session keys established 2322 * for the session using methods {@link #getKeyRequest} and 2323 * {@link #provideKeyResponse} using a session key server. 2324 * 2325 * @param sessionId the session ID for the session containing keys 2326 * to be used for encrypt, decrypt, sign and/or verify 2327 * @param cipherAlgorithm the algorithm to use for encryption and 2328 * decryption ciphers. The algorithm string conforms to JCA Standard 2329 * Names for Cipher Transforms and is case insensitive. For example 2330 * "AES/CBC/NoPadding". 2331 * @param macAlgorithm the algorithm to use for sign and verify 2332 * The algorithm string conforms to JCA Standard Names for Mac 2333 * Algorithms and is case insensitive. For example "HmacSHA256". 2334 * <p> 2335 * The list of supported algorithms for a DRM plugin can be obtained 2336 * using the method {@link #getPropertyString} with the property name 2337 * "algorithms". 2338 */ 2339 public CryptoSession getCryptoSession( 2340 @NonNull byte[] sessionId, 2341 @NonNull String cipherAlgorithm, @NonNull String macAlgorithm) 2342 { 2343 return new CryptoSession(sessionId, cipherAlgorithm, macAlgorithm); 2344 } 2345 2346 /** 2347 * Contains the opaque data an app uses to request a certificate from a provisioning 2348 * server 2349 * 2350 * @hide - not part of the public API at this time 2351 */ 2352 public static final class CertificateRequest { 2353 private byte[] mData; 2354 private String mDefaultUrl; 2355 2356 CertificateRequest(@NonNull byte[] data, @NonNull String defaultUrl) { 2357 mData = data; 2358 mDefaultUrl = defaultUrl; 2359 } 2360 2361 /** 2362 * Get the opaque message data 2363 */ 2364 @NonNull 2365 @UnsupportedAppUsage 2366 public byte[] getData() { return mData; } 2367 2368 /** 2369 * Get the default URL to use when sending the certificate request 2370 * message to a server, if known. The app may prefer to use a different 2371 * certificate server URL obtained from other sources. 2372 */ 2373 @NonNull 2374 @UnsupportedAppUsage 2375 public String getDefaultUrl() { return mDefaultUrl; } 2376 } 2377 2378 /** 2379 * Generate a certificate request, specifying the certificate type 2380 * and authority. The response received should be passed to 2381 * provideCertificateResponse. 2382 * 2383 * @param certType Specifies the certificate type. 2384 * 2385 * @param certAuthority is passed to the certificate server to specify 2386 * the chain of authority. 2387 * 2388 * @hide - not part of the public API at this time 2389 */ 2390 @NonNull 2391 @UnsupportedAppUsage 2392 public CertificateRequest getCertificateRequest( 2393 @CertificateType int certType, @NonNull String certAuthority) 2394 { 2395 ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority); 2396 return new CertificateRequest(provisionRequest.getData(), 2397 provisionRequest.getDefaultUrl()); 2398 } 2399 2400 /** 2401 * Contains the wrapped private key and public certificate data associated 2402 * with a certificate. 2403 * 2404 * @hide - not part of the public API at this time 2405 */ 2406 public static final class Certificate { 2407 Certificate() {} 2408 2409 /** 2410 * Get the wrapped private key data 2411 */ 2412 @NonNull 2413 @UnsupportedAppUsage 2414 public byte[] getWrappedPrivateKey() { 2415 if (mWrappedKey == null) { 2416 // this should never happen as mWrappedKey is initialized in 2417 // JNI after construction of the KeyRequest object. The check 2418 // is needed here to guarantee @NonNull annotation. 2419 throw new RuntimeException("Certificate is not initialized"); 2420 } 2421 return mWrappedKey; 2422 } 2423 2424 /** 2425 * Get the PEM-encoded certificate chain 2426 */ 2427 @NonNull 2428 @UnsupportedAppUsage 2429 public byte[] getContent() { 2430 if (mCertificateData == null) { 2431 // this should never happen as mCertificateData is initialized in 2432 // JNI after construction of the KeyRequest object. The check 2433 // is needed here to guarantee @NonNull annotation. 2434 throw new RuntimeException("Certificate is not initialized"); 2435 } 2436 return mCertificateData; 2437 } 2438 2439 private byte[] mWrappedKey; 2440 private byte[] mCertificateData; 2441 } 2442 2443 2444 /** 2445 * Process a response from the certificate server. The response 2446 * is obtained from an HTTP Post to the url provided by getCertificateRequest. 2447 * <p> 2448 * The public X509 certificate chain and wrapped private key are returned 2449 * in the returned Certificate objec. The certificate chain is in PEM format. 2450 * The wrapped private key should be stored in application private 2451 * storage, and used when invoking the signRSA method. 2452 * 2453 * @param response the opaque certificate response byte array to provide to the 2454 * MediaDrm instance. 2455 * 2456 * @throws DeniedByServerException if the response indicates that the 2457 * server rejected the request 2458 * 2459 * @hide - not part of the public API at this time 2460 */ 2461 @NonNull 2462 @UnsupportedAppUsage 2463 public Certificate provideCertificateResponse(@NonNull byte[] response) 2464 throws DeniedByServerException { 2465 return provideProvisionResponseNative(response); 2466 } 2467 2468 @NonNull 2469 private static final native byte[] signRSANative( 2470 @NonNull MediaDrm drm, @NonNull byte[] sessionId, 2471 @NonNull String algorithm, @NonNull byte[] wrappedKey, @NonNull byte[] message); 2472 2473 /** 2474 * Sign data using an RSA key 2475 * 2476 * @param sessionId a sessionId obtained from openSession on the MediaDrm object 2477 * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1" 2478 * @param wrappedKey - the wrapped (encrypted) RSA private key obtained 2479 * from provideCertificateResponse 2480 * @param message the data for which a signature is to be computed 2481 * 2482 * @hide - not part of the public API at this time 2483 */ 2484 @NonNull 2485 @UnsupportedAppUsage 2486 public byte[] signRSA( 2487 @NonNull byte[] sessionId, @NonNull String algorithm, 2488 @NonNull byte[] wrappedKey, @NonNull byte[] message) { 2489 return signRSANative(this, sessionId, algorithm, wrappedKey, message); 2490 } 2491 2492 /** 2493 * Query if the crypto scheme requires the use of a secure decoder 2494 * to decode data of the given mime type at the default security level. 2495 * The default security level is defined as the highest security level 2496 * supported on the device. 2497 * 2498 * @param mime The mime type of the media data. Please use {@link 2499 * #isCryptoSchemeSupported(UUID, String)} to query mime type support separately; 2500 * for unsupported mime types the return value of {@link 2501 * #requiresSecureDecoder(String)} is crypto scheme dependent. 2502 */ 2503 public boolean requiresSecureDecoder(@NonNull String mime) { 2504 return requiresSecureDecoder(mime, getMaxSecurityLevel()); 2505 } 2506 2507 /** 2508 * Query if the crypto scheme requires the use of a secure decoder 2509 * to decode data of the given mime type at the given security level. 2510 * 2511 * @param mime The mime type of the media data. Please use {@link 2512 * #isCryptoSchemeSupported(UUID, String, int)} to query mime type support 2513 * separately; for unsupported mime types the return value of {@link 2514 * #requiresSecureDecoder(String, int)} is crypto scheme dependent. 2515 * @param level a security level between {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO} 2516 * and {@link #SECURITY_LEVEL_HW_SECURE_ALL}. Otherwise the special value 2517 * {@link #getMaxSecurityLevel()} is also permitted; 2518 * use {@link #getMaxSecurityLevel()} to indicate the maximum security level 2519 * supported by the device. 2520 * @throws IllegalArgumentException if the requested security level is none of the documented 2521 * values for the parameter {@code level}. 2522 */ 2523 public native boolean requiresSecureDecoder(@NonNull String mime, @SecurityLevel int level); 2524 2525 @Override 2526 protected void finalize() throws Throwable { 2527 try { 2528 if (mCloseGuard != null) { 2529 mCloseGuard.warnIfOpen(); 2530 } 2531 release(); 2532 } finally { 2533 super.finalize(); 2534 } 2535 } 2536 2537 /** 2538 * Releases resources associated with the current session of 2539 * MediaDrm. It is considered good practice to call this method when 2540 * the {@link MediaDrm} object is no longer needed in your 2541 * application. After this method is called, {@link MediaDrm} is no 2542 * longer usable since it has lost all of its required resource. 2543 * 2544 * This method was added in API 28. In API versions 18 through 27, release() 2545 * should be called instead. There is no need to do anything for API 2546 * versions prior to 18. 2547 */ 2548 @Override 2549 public void close() { 2550 release(); 2551 } 2552 2553 /** 2554 * @deprecated replaced by {@link #close()}. 2555 */ 2556 @Deprecated 2557 public void release() { 2558 mCloseGuard.close(); 2559 if (mClosed.compareAndSet(false, true)) { 2560 native_release(); 2561 mPlaybackComponentMap.clear(); 2562 } 2563 } 2564 2565 /** @hide */ 2566 public native final void native_release(); 2567 2568 private static native final void native_init(); 2569 2570 private native final void native_setup(Object mediadrm_this, byte[] uuid, 2571 String appPackageName); 2572 2573 static { 2574 System.loadLibrary("media_jni"); 2575 native_init(); 2576 } 2577 2578 /** 2579 * Definitions for the metrics that are reported via the 2580 * {@link #getMetrics} call. 2581 */ 2582 public final static class MetricsConstants 2583 { 2584 private MetricsConstants() {} 2585 2586 /** 2587 * Key to extract the number of successful {@link #openSession} calls 2588 * from the {@link PersistableBundle} returned by a 2589 * {@link #getMetrics} call. 2590 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2591 */ 2592 public static final String OPEN_SESSION_OK_COUNT 2593 = "drm.mediadrm.open_session.ok.count"; 2594 2595 /** 2596 * Key to extract the number of failed {@link #openSession} calls 2597 * from the {@link PersistableBundle} returned by a 2598 * {@link #getMetrics} call. 2599 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2600 */ 2601 public static final String OPEN_SESSION_ERROR_COUNT 2602 = "drm.mediadrm.open_session.error.count"; 2603 2604 /** 2605 * Key to extract the list of error codes that were returned from 2606 * {@link #openSession} calls. The key is used to lookup the list 2607 * in the {@link PersistableBundle} returned by a {@link #getMetrics} 2608 * call. 2609 * The list is an array of Long values 2610 * ({@link android.os.BaseBundle#getLongArray}). 2611 */ 2612 public static final String OPEN_SESSION_ERROR_LIST 2613 = "drm.mediadrm.open_session.error.list"; 2614 2615 /** 2616 * Key to extract the number of successful {@link #closeSession} calls 2617 * from the {@link PersistableBundle} returned by a 2618 * {@link #getMetrics} call. 2619 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2620 */ 2621 public static final String CLOSE_SESSION_OK_COUNT 2622 = "drm.mediadrm.close_session.ok.count"; 2623 2624 /** 2625 * Key to extract the number of failed {@link #closeSession} calls 2626 * from the {@link PersistableBundle} returned by a 2627 * {@link #getMetrics} call. 2628 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2629 */ 2630 public static final String CLOSE_SESSION_ERROR_COUNT 2631 = "drm.mediadrm.close_session.error.count"; 2632 2633 /** 2634 * Key to extract the list of error codes that were returned from 2635 * {@link #closeSession} calls. The key is used to lookup the list 2636 * in the {@link PersistableBundle} returned by a {@link #getMetrics} 2637 * call. 2638 * The list is an array of Long values 2639 * ({@link android.os.BaseBundle#getLongArray}). 2640 */ 2641 public static final String CLOSE_SESSION_ERROR_LIST 2642 = "drm.mediadrm.close_session.error.list"; 2643 2644 /** 2645 * Key to extract the start times of sessions. Times are 2646 * represented as milliseconds since epoch (1970-01-01T00:00:00Z). 2647 * The start times are returned from the {@link PersistableBundle} 2648 * from a {@link #getMetrics} call. 2649 * The start times are returned as another {@link PersistableBundle} 2650 * containing the session ids as keys and the start times as long 2651 * values. Use {@link android.os.BaseBundle#keySet} to get the list of 2652 * session ids, and then {@link android.os.BaseBundle#getLong} to get 2653 * the start time for each session. 2654 */ 2655 public static final String SESSION_START_TIMES_MS 2656 = "drm.mediadrm.session_start_times_ms"; 2657 2658 /** 2659 * Key to extract the end times of sessions. Times are 2660 * represented as milliseconds since epoch (1970-01-01T00:00:00Z). 2661 * The end times are returned from the {@link PersistableBundle} 2662 * from a {@link #getMetrics} call. 2663 * The end times are returned as another {@link PersistableBundle} 2664 * containing the session ids as keys and the end times as long 2665 * values. Use {@link android.os.BaseBundle#keySet} to get the list of 2666 * session ids, and then {@link android.os.BaseBundle#getLong} to get 2667 * the end time for each session. 2668 */ 2669 public static final String SESSION_END_TIMES_MS 2670 = "drm.mediadrm.session_end_times_ms"; 2671 2672 /** 2673 * Key to extract the number of successful {@link #getKeyRequest} calls 2674 * from the {@link PersistableBundle} returned by a 2675 * {@link #getMetrics} call. 2676 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2677 */ 2678 public static final String GET_KEY_REQUEST_OK_COUNT 2679 = "drm.mediadrm.get_key_request.ok.count"; 2680 2681 /** 2682 * Key to extract the number of failed {@link #getKeyRequest} 2683 * calls from the {@link PersistableBundle} returned by a 2684 * {@link #getMetrics} call. 2685 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2686 */ 2687 public static final String GET_KEY_REQUEST_ERROR_COUNT 2688 = "drm.mediadrm.get_key_request.error.count"; 2689 2690 /** 2691 * Key to extract the list of error codes that were returned from 2692 * {@link #getKeyRequest} calls. The key is used to lookup the list 2693 * in the {@link PersistableBundle} returned by a {@link #getMetrics} 2694 * call. 2695 * The list is an array of Long values 2696 * ({@link android.os.BaseBundle#getLongArray}). 2697 */ 2698 public static final String GET_KEY_REQUEST_ERROR_LIST 2699 = "drm.mediadrm.get_key_request.error.list"; 2700 2701 /** 2702 * Key to extract the average time in microseconds of calls to 2703 * {@link #getKeyRequest}. The value is retrieved from the 2704 * {@link PersistableBundle} returned from {@link #getMetrics}. 2705 * The time is a Long value ({@link android.os.BaseBundle#getLong}). 2706 */ 2707 public static final String GET_KEY_REQUEST_OK_TIME_MICROS 2708 = "drm.mediadrm.get_key_request.ok.average_time_micros"; 2709 2710 /** 2711 * Key to extract the number of successful {@link #provideKeyResponse} 2712 * calls from the {@link PersistableBundle} returned by a 2713 * {@link #getMetrics} call. 2714 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2715 */ 2716 public static final String PROVIDE_KEY_RESPONSE_OK_COUNT 2717 = "drm.mediadrm.provide_key_response.ok.count"; 2718 2719 /** 2720 * Key to extract the number of failed {@link #provideKeyResponse} 2721 * calls from the {@link PersistableBundle} returned by a 2722 * {@link #getMetrics} call. 2723 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2724 */ 2725 public static final String PROVIDE_KEY_RESPONSE_ERROR_COUNT 2726 = "drm.mediadrm.provide_key_response.error.count"; 2727 2728 /** 2729 * Key to extract the list of error codes that were returned from 2730 * {@link #provideKeyResponse} calls. The key is used to lookup the 2731 * list in the {@link PersistableBundle} returned by a 2732 * {@link #getMetrics} call. 2733 * The list is an array of Long values 2734 * ({@link android.os.BaseBundle#getLongArray}). 2735 */ 2736 public static final String PROVIDE_KEY_RESPONSE_ERROR_LIST 2737 = "drm.mediadrm.provide_key_response.error.list"; 2738 2739 /** 2740 * Key to extract the average time in microseconds of calls to 2741 * {@link #provideKeyResponse}. The valus is retrieved from the 2742 * {@link PersistableBundle} returned from {@link #getMetrics}. 2743 * The time is a Long value ({@link android.os.BaseBundle#getLong}). 2744 */ 2745 public static final String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS 2746 = "drm.mediadrm.provide_key_response.ok.average_time_micros"; 2747 2748 /** 2749 * Key to extract the number of successful {@link #getProvisionRequest} 2750 * calls from the {@link PersistableBundle} returned by a 2751 * {@link #getMetrics} call. 2752 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2753 */ 2754 public static final String GET_PROVISION_REQUEST_OK_COUNT 2755 = "drm.mediadrm.get_provision_request.ok.count"; 2756 2757 /** 2758 * Key to extract the number of failed {@link #getProvisionRequest} 2759 * calls from the {@link PersistableBundle} returned by a 2760 * {@link #getMetrics} call. 2761 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2762 */ 2763 public static final String GET_PROVISION_REQUEST_ERROR_COUNT 2764 = "drm.mediadrm.get_provision_request.error.count"; 2765 2766 /** 2767 * Key to extract the list of error codes that were returned from 2768 * {@link #getProvisionRequest} calls. The key is used to lookup the 2769 * list in the {@link PersistableBundle} returned by a 2770 * {@link #getMetrics} call. 2771 * The list is an array of Long values 2772 * ({@link android.os.BaseBundle#getLongArray}). 2773 */ 2774 public static final String GET_PROVISION_REQUEST_ERROR_LIST 2775 = "drm.mediadrm.get_provision_request.error.list"; 2776 2777 /** 2778 * Key to extract the number of successful 2779 * {@link #provideProvisionResponse} calls from the 2780 * {@link PersistableBundle} returned by a {@link #getMetrics} call. 2781 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2782 */ 2783 public static final String PROVIDE_PROVISION_RESPONSE_OK_COUNT 2784 = "drm.mediadrm.provide_provision_response.ok.count"; 2785 2786 /** 2787 * Key to extract the number of failed 2788 * {@link #provideProvisionResponse} calls from the 2789 * {@link PersistableBundle} returned by a {@link #getMetrics} call. 2790 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2791 */ 2792 public static final String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT 2793 = "drm.mediadrm.provide_provision_response.error.count"; 2794 2795 /** 2796 * Key to extract the list of error codes that were returned from 2797 * {@link #provideProvisionResponse} calls. The key is used to lookup 2798 * the list in the {@link PersistableBundle} returned by a 2799 * {@link #getMetrics} call. 2800 * The list is an array of Long values 2801 * ({@link android.os.BaseBundle#getLongArray}). 2802 */ 2803 public static final String PROVIDE_PROVISION_RESPONSE_ERROR_LIST 2804 = "drm.mediadrm.provide_provision_response.error.list"; 2805 2806 /** 2807 * Key to extract the number of successful 2808 * {@link #getPropertyByteArray} calls were made with the 2809 * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup 2810 * the value in the {@link PersistableBundle} returned by a 2811 * {@link #getMetrics} call. 2812 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2813 */ 2814 public static final String GET_DEVICE_UNIQUE_ID_OK_COUNT 2815 = "drm.mediadrm.get_device_unique_id.ok.count"; 2816 2817 /** 2818 * Key to extract the number of failed 2819 * {@link #getPropertyByteArray} calls were made with the 2820 * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup 2821 * the value in the {@link PersistableBundle} returned by a 2822 * {@link #getMetrics} call. 2823 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2824 */ 2825 public static final String GET_DEVICE_UNIQUE_ID_ERROR_COUNT 2826 = "drm.mediadrm.get_device_unique_id.error.count"; 2827 2828 /** 2829 * Key to extract the list of error codes that were returned from 2830 * {@link #getPropertyByteArray} calls with the 2831 * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup 2832 * the list in the {@link PersistableBundle} returned by a 2833 * {@link #getMetrics} call. 2834 * The list is an array of Long values 2835 * ({@link android.os.BaseBundle#getLongArray}). 2836 */ 2837 public static final String GET_DEVICE_UNIQUE_ID_ERROR_LIST 2838 = "drm.mediadrm.get_device_unique_id.error.list"; 2839 2840 /** 2841 * Key to extraact the count of {@link KeyStatus#STATUS_EXPIRED} events 2842 * that occured. The count is extracted from the 2843 * {@link PersistableBundle} returned from a {@link #getMetrics} call. 2844 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2845 */ 2846 public static final String KEY_STATUS_EXPIRED_COUNT 2847 = "drm.mediadrm.key_status.EXPIRED.count"; 2848 2849 /** 2850 * Key to extract the count of {@link KeyStatus#STATUS_INTERNAL_ERROR} 2851 * events that occured. The count is extracted from the 2852 * {@link PersistableBundle} returned from a {@link #getMetrics} call. 2853 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2854 */ 2855 public static final String KEY_STATUS_INTERNAL_ERROR_COUNT 2856 = "drm.mediadrm.key_status.INTERNAL_ERROR.count"; 2857 2858 /** 2859 * Key to extract the count of 2860 * {@link KeyStatus#STATUS_OUTPUT_NOT_ALLOWED} events that occured. 2861 * The count is extracted from the 2862 * {@link PersistableBundle} returned from a {@link #getMetrics} call. 2863 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2864 */ 2865 public static final String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT 2866 = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count"; 2867 2868 /** 2869 * Key to extract the count of {@link KeyStatus#STATUS_PENDING} 2870 * events that occured. The count is extracted from the 2871 * {@link PersistableBundle} returned from a {@link #getMetrics} call. 2872 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2873 */ 2874 public static final String KEY_STATUS_PENDING_COUNT 2875 = "drm.mediadrm.key_status_change.PENDING.count"; 2876 2877 /** 2878 * Key to extract the count of {@link KeyStatus#STATUS_USABLE} 2879 * events that occured. The count is extracted from the 2880 * {@link PersistableBundle} returned from a {@link #getMetrics} call. 2881 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2882 */ 2883 public static final String KEY_STATUS_USABLE_COUNT 2884 = "drm.mediadrm.key_status_change.USABLE.count"; 2885 2886 /** 2887 * Key to extract the count of {@link OnEventListener#onEvent} 2888 * calls of type PROVISION_REQUIRED occured. The count is 2889 * extracted from the {@link PersistableBundle} returned from a 2890 * {@link #getMetrics} call. 2891 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2892 */ 2893 public static final String EVENT_PROVISION_REQUIRED_COUNT 2894 = "drm.mediadrm.event.PROVISION_REQUIRED.count"; 2895 2896 /** 2897 * Key to extract the count of {@link OnEventListener#onEvent} 2898 * calls of type KEY_NEEDED occured. The count is 2899 * extracted from the {@link PersistableBundle} returned from a 2900 * {@link #getMetrics} call. 2901 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2902 */ 2903 public static final String EVENT_KEY_NEEDED_COUNT 2904 = "drm.mediadrm.event.KEY_NEEDED.count"; 2905 2906 /** 2907 * Key to extract the count of {@link OnEventListener#onEvent} 2908 * calls of type KEY_EXPIRED occured. The count is 2909 * extracted from the {@link PersistableBundle} returned from a 2910 * {@link #getMetrics} call. 2911 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2912 */ 2913 public static final String EVENT_KEY_EXPIRED_COUNT 2914 = "drm.mediadrm.event.KEY_EXPIRED.count"; 2915 2916 /** 2917 * Key to extract the count of {@link OnEventListener#onEvent} 2918 * calls of type VENDOR_DEFINED. The count is 2919 * extracted from the {@link PersistableBundle} returned from a 2920 * {@link #getMetrics} call. 2921 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2922 */ 2923 public static final String EVENT_VENDOR_DEFINED_COUNT 2924 = "drm.mediadrm.event.VENDOR_DEFINED.count"; 2925 2926 /** 2927 * Key to extract the count of {@link OnEventListener#onEvent} 2928 * calls of type SESSION_RECLAIMED. The count is 2929 * extracted from the {@link PersistableBundle} returned from a 2930 * {@link #getMetrics} call. 2931 * The count is a Long value ({@link android.os.BaseBundle#getLong}). 2932 */ 2933 public static final String EVENT_SESSION_RECLAIMED_COUNT 2934 = "drm.mediadrm.event.SESSION_RECLAIMED.count"; 2935 } 2936 2937 /** 2938 * Obtain a {@link PlaybackComponent} associated with a DRM session. 2939 * Call {@link PlaybackComponent#setLogSessionId(LogSessionId)} on 2940 * the returned object to associate a playback session with the DRM session. 2941 * 2942 * @param sessionId a DRM session ID obtained from {@link #openSession()} 2943 * @return a {@link PlaybackComponent} associated with the session, 2944 * or {@code null} if the session is closed or does not exist. 2945 * @see PlaybackComponent 2946 */ 2947 @Nullable 2948 public PlaybackComponent getPlaybackComponent(@NonNull byte[] sessionId) { 2949 if (sessionId == null) { 2950 throw new IllegalArgumentException("sessionId is null"); 2951 } 2952 return mPlaybackComponentMap.get(ByteBuffer.wrap(sessionId)); 2953 } 2954 2955 private native void setPlaybackId(byte[] sessionId, String logSessionId); 2956 2957 /** This class contains the Drm session ID and log session ID */ 2958 public final class PlaybackComponent { 2959 private final byte[] mSessionId; 2960 @NonNull private LogSessionId mLogSessionId = LogSessionId.LOG_SESSION_ID_NONE; 2961 2962 /** @hide */ 2963 public PlaybackComponent(byte[] sessionId) { 2964 mSessionId = sessionId; 2965 } 2966 2967 2968 /** 2969 * Gets the {@link LogSessionId}. 2970 */ 2971 public void setLogSessionId(@NonNull LogSessionId logSessionId) { 2972 Objects.requireNonNull(logSessionId); 2973 if (logSessionId.getStringId() == null) { 2974 throw new IllegalArgumentException("playbackId is null"); 2975 } 2976 MediaDrm.this.setPlaybackId(mSessionId, logSessionId.getStringId()); 2977 mLogSessionId = logSessionId; 2978 } 2979 2980 2981 /** 2982 * Returns the {@link LogSessionId}. 2983 */ 2984 @NonNull public LogSessionId getLogSessionId() { 2985 return mLogSessionId; 2986 } 2987 } 2988 2989 /** 2990 * Returns recent {@link LogMessage LogMessages} associated with this {@link MediaDrm} 2991 * instance. 2992 */ 2993 @NonNull 2994 public native List<LogMessage> getLogMessages(); 2995 2996 /** 2997 * A {@link LogMessage} records an event in the {@link MediaDrm} framework 2998 * or vendor plugin. 2999 */ 3000 public static final class LogMessage { 3001 private final long timestampMillis; 3002 private final int priority; 3003 private final String message; 3004 3005 /** 3006 * Timing of the recorded event measured in milliseconds since the Epoch, 3007 * 1970-01-01 00:00:00 +0000 (UTC). 3008 */ 3009 public final long getTimestampMillis() { return timestampMillis; } 3010 3011 /** 3012 * Priority of the recorded event. 3013 * <p> 3014 * Possible priority constants are defined in {@link Log}, e.g.: 3015 * <ul> 3016 * <li>{@link Log#ASSERT}</li> 3017 * <li>{@link Log#ERROR}</li> 3018 * <li>{@link Log#WARN}</li> 3019 * <li>{@link Log#INFO}</li> 3020 * <li>{@link Log#DEBUG}</li> 3021 * <li>{@link Log#VERBOSE}</li> 3022 * </ul> 3023 */ 3024 @Log.Level 3025 public final int getPriority() { return priority; } 3026 3027 /** 3028 * Description of the recorded event. 3029 */ 3030 @NonNull 3031 public final String getMessage() { return message; } 3032 3033 private LogMessage(long timestampMillis, int priority, String message) { 3034 this.timestampMillis = timestampMillis; 3035 if (priority < Log.VERBOSE || priority > Log.ASSERT) { 3036 throw new IllegalArgumentException("invalid log priority " + priority); 3037 } 3038 this.priority = priority; 3039 this.message = message; 3040 } 3041 3042 private char logPriorityChar() { 3043 switch (priority) { 3044 case Log.VERBOSE: 3045 return 'V'; 3046 case Log.DEBUG: 3047 return 'D'; 3048 case Log.INFO: 3049 return 'I'; 3050 case Log.WARN: 3051 return 'W'; 3052 case Log.ERROR: 3053 return 'E'; 3054 case Log.ASSERT: 3055 return 'F'; 3056 default: 3057 } 3058 return 'U'; 3059 } 3060 3061 @Override 3062 public String toString() { 3063 return String.format("LogMessage{%s %c %s}", 3064 Instant.ofEpochMilli(timestampMillis), logPriorityChar(), message); 3065 } 3066 } 3067 } 3068