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