Home | History | Annotate | Download | only in media
      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.IntDef;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.annotation.StringDef;
     23 import android.annotation.SystemApi;
     24 import android.app.ActivityThread;
     25 import android.os.Handler;
     26 import android.os.Looper;
     27 import android.os.Message;
     28 import android.os.Parcel;
     29 import android.os.PersistableBundle;
     30 import android.util.Log;
     31 import dalvik.system.CloseGuard;
     32 import java.lang.annotation.Retention;
     33 import java.lang.annotation.RetentionPolicy;
     34 import java.lang.ref.WeakReference;
     35 import java.util.ArrayList;
     36 import java.util.HashMap;
     37 import java.util.List;
     38 import java.util.UUID;
     39 import java.util.concurrent.atomic.AtomicBoolean;
     40 
     41 
     42 /**
     43  * MediaDrm can be used to obtain keys for decrypting protected media streams, in
     44  * conjunction with {@link android.media.MediaCrypto}.  The MediaDrm APIs
     45  * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
     46  * may also be used to implement other encryption schemes.
     47  * <p>
     48  * Encrypted content is prepared using an encryption server and stored in a content
     49  * library. The encrypted content is streamed or downloaded from the content library to
     50  * client devices via content servers.  Licenses to view the content are obtained from
     51  * a License Server.
     52  * <p>
     53  * <p><img src="../../../images/mediadrm_overview.png"
     54  *      alt="MediaDrm Overview diagram"
     55  *      border="0" /></p>
     56  * <p>
     57  * Keys are requested from the license server using a key request. The key
     58  * response is delivered to the client app, which provides the response to the
     59  * MediaDrm API.
     60  * <p>
     61  * A Provisioning server may be required to distribute device-unique credentials to
     62  * the devices.
     63  * <p>
     64  * Enforcing requirements related to the number of devices that may play content
     65  * simultaneously can be performed either through key renewal or using the secure
     66  * stop methods.
     67  * <p>
     68  * The following sequence diagram shows the interactions between the objects
     69  * involved while playing back encrypted content:
     70  * <p>
     71  * <p><img src="../../../images/mediadrm_decryption_sequence.png"
     72  *         alt="MediaDrm Overview diagram"
     73  *         border="0" /></p>
     74  * <p>
     75  * The app first constructs {@link android.media.MediaExtractor} and
     76  * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
     77  * typically from metadata in the content, and uses this UUID to construct an instance
     78  * of a MediaDrm object that is able to support the DRM scheme required by the content.
     79  * Crypto schemes are assigned 16 byte UUIDs.  The method {@link #isCryptoSchemeSupported}
     80  * can be used to query if a given scheme is supported on the device.
     81  * <p>
     82  * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
     83  * the session in subsequent interactions. The app next uses the MediaDrm object to
     84  * obtain a key request message and send it to the license server, then provide
     85  * the server's response to the MediaDrm object.
     86  * <p>
     87  * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
     88  * sessionId.  The MediaCrypto object is registered with the MediaCodec in the
     89  * {@link MediaCodec#configure} method to enable the codec to decrypt content.
     90  * <p>
     91  * When the app has constructed {@link android.media.MediaExtractor},
     92  * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
     93  * it proceeds to pull samples from the extractor and queue them into the decoder.  For
     94  * encrypted content, the samples returned from the extractor remain encrypted, they
     95  * are only decrypted when the samples are delivered to the decoder.
     96  * <p>
     97  * MediaDrm methods throw {@link android.media.MediaDrm.MediaDrmStateException}
     98  * when a method is called on a MediaDrm object that has had an unrecoverable failure
     99  * in the DRM plugin or security hardware.
    100  * {@link android.media.MediaDrm.MediaDrmStateException} extends
    101  * {@link java.lang.IllegalStateException} with the addition of a developer-readable
    102  * diagnostic information string associated with the exception.
    103  * <p>
    104  * In the event of a mediaserver process crash or restart while a MediaDrm object
    105  * is active, MediaDrm methods may throw {@link android.media.MediaDrmResetException}.
    106  * To recover, the app must release the MediaDrm object, then create and initialize
    107  * a new one.
    108  * <p>
    109  * As {@link android.media.MediaDrmResetException} and
    110  * {@link android.media.MediaDrm.MediaDrmStateException} both extend
    111  * {@link java.lang.IllegalStateException}, they should be in an earlier catch()
    112  * block than {@link java.lang.IllegalStateException} if handled separately.
    113  * <p>
    114  * <a name="Callbacks"></a>
    115  * <h3>Callbacks</h3>
    116  * <p>Applications should register for informational events in order
    117  * to be informed of key state updates during playback or streaming.
    118  * Registration for these events is done via a call to
    119  * {@link #setOnEventListener}. In order to receive the respective
    120  * callback associated with this listener, applications are required to create
    121  * MediaDrm objects on a thread with its own Looper running (main UI
    122  * thread by default has a Looper running).
    123  */
    124 public final class MediaDrm implements AutoCloseable {
    125 
    126     private static final String TAG = "MediaDrm";
    127 
    128     private final AtomicBoolean mClosed = new AtomicBoolean();
    129     private final CloseGuard mCloseGuard = CloseGuard.get();
    130 
    131     private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
    132 
    133     private EventHandler mEventHandler;
    134     private EventHandler mOnKeyStatusChangeEventHandler;
    135     private EventHandler mOnExpirationUpdateEventHandler;
    136     private OnEventListener mOnEventListener;
    137     private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
    138     private OnExpirationUpdateListener mOnExpirationUpdateListener;
    139 
    140     private long mNativeContext;
    141 
    142     /**
    143      * Specify no certificate type
    144      *
    145      * @hide - not part of the public API at this time
    146      */
    147     public static final int CERTIFICATE_TYPE_NONE = 0;
    148 
    149     /**
    150      * Specify X.509 certificate type
    151      *
    152      * @hide - not part of the public API at this time
    153      */
    154     public static final int CERTIFICATE_TYPE_X509 = 1;
    155 
    156     /** @hide */
    157     @IntDef({
    158         CERTIFICATE_TYPE_NONE,
    159         CERTIFICATE_TYPE_X509,
    160     })
    161     @Retention(RetentionPolicy.SOURCE)
    162     public @interface CertificateType {}
    163 
    164     /**
    165      * Query if the given scheme identified by its UUID is supported on
    166      * this device.
    167      * @param uuid The UUID of the crypto scheme.
    168      */
    169     public static final boolean isCryptoSchemeSupported(@NonNull UUID uuid) {
    170         return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), null);
    171     }
    172 
    173     /**
    174      * Query if the given scheme identified by its UUID is supported on
    175      * this device, and whether the DRM plugin is able to handle the
    176      * media container format specified by mimeType.
    177      * @param uuid The UUID of the crypto scheme.
    178      * @param mimeType The MIME type of the media container, e.g. "video/mp4"
    179      *   or "video/webm"
    180      */
    181     public static final boolean isCryptoSchemeSupported(
    182             @NonNull UUID uuid, @NonNull String mimeType) {
    183         return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid), mimeType);
    184     }
    185 
    186     private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) {
    187         long msb = uuid.getMostSignificantBits();
    188         long lsb = uuid.getLeastSignificantBits();
    189 
    190         byte[] uuidBytes = new byte[16];
    191         for (int i = 0; i < 8; ++i) {
    192             uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
    193             uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
    194         }
    195 
    196         return uuidBytes;
    197     }
    198 
    199     private static final native boolean isCryptoSchemeSupportedNative(
    200             @NonNull byte[] uuid, @Nullable String mimeType);
    201 
    202     /**
    203      * Instantiate a MediaDrm object
    204      *
    205      * @param uuid The UUID of the crypto scheme.
    206      *
    207      * @throws UnsupportedSchemeException if the device does not support the
    208      * specified scheme UUID
    209      */
    210     public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException {
    211         Looper looper;
    212         if ((looper = Looper.myLooper()) != null) {
    213             mEventHandler = new EventHandler(this, looper);
    214         } else if ((looper = Looper.getMainLooper()) != null) {
    215             mEventHandler = new EventHandler(this, looper);
    216         } else {
    217             mEventHandler = null;
    218         }
    219 
    220         /* Native setup requires a weak reference to our object.
    221          * It's easier to create it here than in C++.
    222          */
    223         native_setup(new WeakReference<MediaDrm>(this),
    224                 getByteArrayFromUUID(uuid),  ActivityThread.currentOpPackageName());
    225 
    226         mCloseGuard.open("release");
    227     }
    228 
    229     /**
    230      * Thrown when an unrecoverable failure occurs during a MediaDrm operation.
    231      * Extends java.lang.IllegalStateException with the addition of an error
    232      * code that may be useful in diagnosing the failure.
    233      */
    234     public static final class MediaDrmStateException extends java.lang.IllegalStateException {
    235         private final int mErrorCode;
    236         private final String mDiagnosticInfo;
    237 
    238         /**
    239          * @hide
    240          */
    241         public MediaDrmStateException(int errorCode, @Nullable String detailMessage) {
    242             super(detailMessage);
    243             mErrorCode = errorCode;
    244 
    245             // TODO get this from DRM session
    246             final String sign = errorCode < 0 ? "neg_" : "";
    247             mDiagnosticInfo =
    248                 "android.media.MediaDrm.error_" + sign + Math.abs(errorCode);
    249 
    250         }
    251 
    252         /**
    253          * Retrieve the associated error code
    254          *
    255          * @hide
    256          */
    257         public int getErrorCode() {
    258             return mErrorCode;
    259         }
    260 
    261         /**
    262          * Retrieve a developer-readable diagnostic information string
    263          * associated with the exception. Do not show this to end-users,
    264          * since this string will not be localized or generally comprehensible
    265          * to end-users.
    266          */
    267         @NonNull
    268         public String getDiagnosticInfo() {
    269             return mDiagnosticInfo;
    270         }
    271     }
    272 
    273     /**
    274      * Register a callback to be invoked when a session expiration update
    275      * occurs.  The app's OnExpirationUpdateListener will be notified
    276      * when the expiration time of the keys in the session have changed.
    277      * @param listener the callback that will be run, or {@code null} to unregister the
    278      *     previously registered callback.
    279      * @param handler the handler on which the listener should be invoked, or
    280      *     {@code null} if the listener should be invoked on the calling thread's looper.
    281      */
    282     public void setOnExpirationUpdateListener(
    283             @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) {
    284         if (listener != null) {
    285             Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
    286             if (looper != null) {
    287                 if (mEventHandler == null || mEventHandler.getLooper() != looper) {
    288                     mEventHandler = new EventHandler(this, looper);
    289                 }
    290             }
    291         }
    292         mOnExpirationUpdateListener = listener;
    293     }
    294 
    295     /**
    296      * Interface definition for a callback to be invoked when a drm session
    297      * expiration update occurs
    298      */
    299     public interface OnExpirationUpdateListener
    300     {
    301         /**
    302          * Called when a session expiration update occurs, to inform the app
    303          * about the change in expiration time
    304          *
    305          * @param md the MediaDrm object on which the event occurred
    306          * @param sessionId the DRM session ID on which the event occurred
    307          * @param expirationTime the new expiration time for the keys in the session.
    308          *     The time is in milliseconds, relative to the Unix epoch.  A time of
    309          *     0 indicates that the keys never expire.
    310          */
    311         void onExpirationUpdate(
    312                 @NonNull MediaDrm md, @NonNull byte[] sessionId, long expirationTime);
    313     }
    314 
    315     /**
    316      * Register a callback to be invoked when the state of keys in a session
    317      * change, e.g. when a license update occurs or when a license expires.
    318      *
    319      * @param listener the callback that will be run when key status changes, or
    320      *     {@code null} to unregister the previously registered callback.
    321      * @param handler the handler on which the listener should be invoked, or
    322      *     null if the listener should be invoked on the calling thread's looper.
    323      */
    324     public void setOnKeyStatusChangeListener(
    325             @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
    326         if (listener != null) {
    327             Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
    328             if (looper != null) {
    329                 if (mEventHandler == null || mEventHandler.getLooper() != looper) {
    330                     mEventHandler = new EventHandler(this, looper);
    331                 }
    332             }
    333         }
    334         mOnKeyStatusChangeListener = listener;
    335     }
    336 
    337     /**
    338      * Interface definition for a callback to be invoked when the keys in a drm
    339      * session change states.
    340      */
    341     public interface OnKeyStatusChangeListener
    342     {
    343         /**
    344          * Called when the keys in a session change status, such as when the license
    345          * is renewed or expires.
    346          *
    347          * @param md the MediaDrm object on which the event occurred
    348          * @param sessionId the DRM session ID on which the event occurred
    349          * @param keyInformation a list of {@link MediaDrm.KeyStatus}
    350          *     instances indicating the status for each key in the session
    351          * @param hasNewUsableKey indicates if a key has been added that is usable,
    352          *     which may trigger an attempt to resume playback on the media stream
    353          *     if it is currently blocked waiting for a key.
    354          */
    355         void onKeyStatusChange(
    356                 @NonNull MediaDrm md, @NonNull byte[] sessionId,
    357                 @NonNull List<KeyStatus> keyInformation,
    358                 boolean hasNewUsableKey);
    359     }
    360 
    361     /**
    362      * Defines the status of a key.
    363      * A KeyStatus for each key in a session is provided to the
    364      * {@link OnKeyStatusChangeListener#onKeyStatusChange}
    365      * listener.
    366      */
    367     public static final class KeyStatus {
    368         private final byte[] mKeyId;
    369         private final int mStatusCode;
    370 
    371         /**
    372          * The key is currently usable to decrypt media data
    373          */
    374         public static final int STATUS_USABLE = 0;
    375 
    376         /**
    377          * The key is no longer usable to decrypt media data because its
    378          * expiration time has passed.
    379          */
    380         public static final int STATUS_EXPIRED = 1;
    381 
    382         /**
    383          * The key is not currently usable to decrypt media data because its
    384          * output requirements cannot currently be met.
    385          */
    386         public static final int STATUS_OUTPUT_NOT_ALLOWED = 2;
    387 
    388         /**
    389          * The status of the key is not yet known and is being determined.
    390          * The status will be updated with the actual status when it has
    391          * been determined.
    392          */
    393         public static final int STATUS_PENDING = 3;
    394 
    395         /**
    396          * The key is not currently usable to decrypt media data because of an
    397          * internal error in processing unrelated to input parameters.  This error
    398          * is not actionable by an app.
    399          */
    400         public static final int STATUS_INTERNAL_ERROR = 4;
    401 
    402         /** @hide */
    403         @IntDef({
    404             STATUS_USABLE,
    405             STATUS_EXPIRED,
    406             STATUS_OUTPUT_NOT_ALLOWED,
    407             STATUS_PENDING,
    408             STATUS_INTERNAL_ERROR,
    409         })
    410         @Retention(RetentionPolicy.SOURCE)
    411         public @interface KeyStatusCode {}
    412 
    413         KeyStatus(@NonNull byte[] keyId, @KeyStatusCode int statusCode) {
    414             mKeyId = keyId;
    415             mStatusCode = statusCode;
    416         }
    417 
    418         /**
    419          * Returns the status code for the key
    420          * @return one of {@link #STATUS_USABLE}, {@link #STATUS_EXPIRED},
    421          * {@link #STATUS_OUTPUT_NOT_ALLOWED}, {@link #STATUS_PENDING}
    422          * or {@link #STATUS_INTERNAL_ERROR}.
    423          */
    424         @KeyStatusCode
    425         public int getStatusCode() { return mStatusCode; }
    426 
    427         /**
    428          * Returns the id for the key
    429          */
    430         @NonNull
    431         public byte[] getKeyId() { return mKeyId; }
    432     }
    433 
    434     /**
    435      * Register a callback to be invoked when an event occurs
    436      *
    437      * @param listener the callback that will be run.  Use {@code null} to
    438      *        stop receiving event callbacks.
    439      */
    440     public void setOnEventListener(@Nullable OnEventListener listener)
    441     {
    442         mOnEventListener = listener;
    443     }
    444 
    445     /**
    446      * Interface definition for a callback to be invoked when a drm event
    447      * occurs
    448      */
    449     public interface OnEventListener
    450     {
    451         /**
    452          * Called when an event occurs that requires the app to be notified
    453          *
    454          * @param md the MediaDrm object on which the event occurred
    455          * @param sessionId the DRM session ID on which the event occurred,
    456          *        or {@code null} if there is no session ID associated with the event.
    457          * @param event indicates the event type
    458          * @param extra an secondary error code
    459          * @param data optional byte array of data that may be associated with the event
    460          */
    461         void onEvent(
    462                 @NonNull MediaDrm md, @Nullable byte[] sessionId,
    463                 @DrmEvent int event, int extra,
    464                 @Nullable byte[] data);
    465     }
    466 
    467     /**
    468      * This event type indicates that the app needs to request a certificate from
    469      * the provisioning server.  The request message data is obtained using
    470      * {@link #getProvisionRequest}
    471      *
    472      * @deprecated Handle provisioning via {@link android.media.NotProvisionedException}
    473      * instead.
    474      */
    475     public static final int EVENT_PROVISION_REQUIRED = 1;
    476 
    477     /**
    478      * This event type indicates that the app needs to request keys from a license
    479      * server.  The request message data is obtained using {@link #getKeyRequest}.
    480      */
    481     public static final int EVENT_KEY_REQUIRED = 2;
    482 
    483     /**
    484      * This event type indicates that the licensed usage duration for keys in a session
    485      * has expired.  The keys are no longer valid.
    486      * @deprecated Use {@link OnKeyStatusChangeListener#onKeyStatusChange}
    487      * and check for {@link MediaDrm.KeyStatus#STATUS_EXPIRED} in the {@link MediaDrm.KeyStatus}
    488      * instead.
    489      */
    490     public static final int EVENT_KEY_EXPIRED = 3;
    491 
    492     /**
    493      * This event may indicate some specific vendor-defined condition, see your
    494      * DRM provider documentation for details
    495      */
    496     public static final int EVENT_VENDOR_DEFINED = 4;
    497 
    498     /**
    499      * This event indicates that a session opened by the app has been reclaimed by the resource
    500      * manager.
    501      */
    502     public static final int EVENT_SESSION_RECLAIMED = 5;
    503 
    504     /** @hide */
    505     @IntDef({
    506         EVENT_PROVISION_REQUIRED,
    507         EVENT_KEY_REQUIRED,
    508         EVENT_KEY_EXPIRED,
    509         EVENT_VENDOR_DEFINED,
    510         EVENT_SESSION_RECLAIMED,
    511     })
    512     @Retention(RetentionPolicy.SOURCE)
    513     public @interface DrmEvent {}
    514 
    515     private static final int DRM_EVENT = 200;
    516     private static final int EXPIRATION_UPDATE = 201;
    517     private static final int KEY_STATUS_CHANGE = 202;
    518 
    519     private class EventHandler extends Handler
    520     {
    521         private MediaDrm mMediaDrm;
    522 
    523         public EventHandler(@NonNull MediaDrm md, @NonNull Looper looper) {
    524             super(looper);
    525             mMediaDrm = md;
    526         }
    527 
    528         @Override
    529         public void handleMessage(@NonNull Message msg) {
    530             if (mMediaDrm.mNativeContext == 0) {
    531                 Log.w(TAG, "MediaDrm went away with unhandled events");
    532                 return;
    533             }
    534             switch(msg.what) {
    535 
    536             case DRM_EVENT:
    537                 if (mOnEventListener != null) {
    538                     if (msg.obj != null && msg.obj instanceof Parcel) {
    539                         Parcel parcel = (Parcel)msg.obj;
    540                         byte[] sessionId = parcel.createByteArray();
    541                         if (sessionId.length == 0) {
    542                             sessionId = null;
    543                         }
    544                         byte[] data = parcel.createByteArray();
    545                         if (data.length == 0) {
    546                             data = null;
    547                         }
    548 
    549                         Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
    550                         mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
    551                     }
    552                 }
    553                 return;
    554 
    555             case KEY_STATUS_CHANGE:
    556                 if (mOnKeyStatusChangeListener != null) {
    557                     if (msg.obj != null && msg.obj instanceof Parcel) {
    558                         Parcel parcel = (Parcel)msg.obj;
    559                         byte[] sessionId = parcel.createByteArray();
    560                         if (sessionId.length > 0) {
    561                             List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
    562                             boolean hasNewUsableKey = (parcel.readInt() != 0);
    563 
    564                             Log.i(TAG, "Drm key status changed");
    565                             mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
    566                                     keyStatusList, hasNewUsableKey);
    567                         }
    568                     }
    569                 }
    570                 return;
    571 
    572             case EXPIRATION_UPDATE:
    573                 if (mOnExpirationUpdateListener != null) {
    574                     if (msg.obj != null && msg.obj instanceof Parcel) {
    575                         Parcel parcel = (Parcel)msg.obj;
    576                         byte[] sessionId = parcel.createByteArray();
    577                         if (sessionId.length > 0) {
    578                             long expirationTime = parcel.readLong();
    579 
    580                             Log.i(TAG, "Drm key expiration update: " + expirationTime);
    581                             mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
    582                                     expirationTime);
    583                         }
    584                     }
    585                 }
    586                 return;
    587 
    588             default:
    589                 Log.e(TAG, "Unknown message type " + msg.what);
    590                 return;
    591             }
    592         }
    593     }
    594 
    595     /**
    596      * Parse a list of KeyStatus objects from an event parcel
    597      */
    598     @NonNull
    599     private List<KeyStatus> keyStatusListFromParcel(@NonNull Parcel parcel) {
    600         int nelems = parcel.readInt();
    601         List<KeyStatus> keyStatusList = new ArrayList(nelems);
    602         while (nelems-- > 0) {
    603             byte[] keyId = parcel.createByteArray();
    604             int keyStatusCode = parcel.readInt();
    605             keyStatusList.add(new KeyStatus(keyId, keyStatusCode));
    606         }
    607         return keyStatusList;
    608     }
    609 
    610     /**
    611      * This method is called from native code when an event occurs.  This method
    612      * just uses the EventHandler system to post the event back to the main app thread.
    613      * We use a weak reference to the original MediaPlayer object so that the native
    614      * code is safe from the object disappearing from underneath it.  (This is
    615      * the cookie passed to native_setup().)
    616      */
    617     private static void postEventFromNative(@NonNull Object mediadrm_ref,
    618             int what, int eventType, int extra, @Nullable Object obj)
    619     {
    620         MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get();
    621         if (md == null) {
    622             return;
    623         }
    624         if (md.mEventHandler != null) {
    625             Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
    626             md.mEventHandler.sendMessage(m);
    627         }
    628     }
    629 
    630     /**
    631      * Open a new session with the MediaDrm object. A session ID is returned.
    632      * By default, sessions are opened at the native security level of the device.
    633      *
    634      * @throws NotProvisionedException if provisioning is needed
    635      * @throws ResourceBusyException if required resources are in use
    636      */
    637     @NonNull
    638     public byte[] openSession() throws NotProvisionedException,
    639             ResourceBusyException {
    640         return openSession(getMaxSecurityLevel());
    641     }
    642 
    643     /**
    644      * Open a new session at a requested security level. The security level
    645      * represents the robustness of the device's DRM implementation. By default,
    646      * sessions are opened at the native security level of the device.
    647      * Overriding the security level is necessary when the decrypted frames need
    648      * to be manipulated, such as for image compositing. The security level
    649      * parameter must be lower than the native level. Reducing the security
    650      * level will typically limit the content to lower resolutions, as
    651      * determined by the license policy. If the requested level is not
    652      * supported, the next lower supported security level will be set. The level
    653      * can be queried using {@link #getSecurityLevel}. A session
    654      * ID is returned.
    655      *
    656      * @param level the new security level, one of
    657      * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO},
    658      * {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
    659      * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO},
    660      * {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or
    661      * {@link #SECURITY_LEVEL_HW_SECURE_ALL}.
    662      *
    663      * @throws NotProvisionedException if provisioning is needed
    664      * @throws ResourceBusyException if required resources are in use
    665      * @throws IllegalArgumentException if the requested security level is
    666      * higher than the native level or lower than the lowest supported level or
    667      * if the device does not support specifying the security level when opening
    668      * a session
    669      */
    670     @NonNull
    671     public native byte[] openSession(@SecurityLevel int level) throws
    672             NotProvisionedException, ResourceBusyException;
    673 
    674     /**
    675      * Close a session on the MediaDrm object that was previously opened
    676      * with {@link #openSession}.
    677      */
    678     public native void closeSession(@NonNull byte[] sessionId);
    679 
    680     /**
    681      * This key request type species that the keys will be for online use, they will
    682      * not be saved to the device for subsequent use when the device is not connected
    683      * to a network.
    684      */
    685     public static final int KEY_TYPE_STREAMING = 1;
    686 
    687     /**
    688      * This key request type specifies that the keys will be for offline use, they
    689      * will be saved to the device for use when the device is not connected to a network.
    690      */
    691     public static final int KEY_TYPE_OFFLINE = 2;
    692 
    693     /**
    694      * This key request type specifies that previously saved offline keys should be released.
    695      */
    696     public static final int KEY_TYPE_RELEASE = 3;
    697 
    698     /** @hide */
    699     @IntDef({
    700         KEY_TYPE_STREAMING,
    701         KEY_TYPE_OFFLINE,
    702         KEY_TYPE_RELEASE,
    703     })
    704     @Retention(RetentionPolicy.SOURCE)
    705     public @interface KeyType {}
    706 
    707     /**
    708      * Contains the opaque data an app uses to request keys from a license server.
    709      * These request types may or may not be generated by a given plugin. Refer
    710      * to plugin vendor documentation for more information.
    711      */
    712     public static final class KeyRequest {
    713         private byte[] mData;
    714         private String mDefaultUrl;
    715         private int mRequestType;
    716 
    717         /**
    718          * Key request type is initial license request. A license request
    719          * is necessary to load keys.
    720          */
    721         public static final int REQUEST_TYPE_INITIAL = 0;
    722 
    723         /**
    724          * Key request type is license renewal. A license request is
    725          * necessary to prevent the keys from expiring.
    726          */
    727         public static final int REQUEST_TYPE_RENEWAL = 1;
    728 
    729         /**
    730          * Key request type is license release
    731          */
    732         public static final int REQUEST_TYPE_RELEASE = 2;
    733 
    734         /**
    735          * Keys are already loaded and are available for use. No license request is necessary, and
    736          * no key request data is returned.
    737          */
    738         public static final int REQUEST_TYPE_NONE = 3;
    739 
    740         /**
    741          * Keys have been loaded but an additional license request is needed
    742          * to update their values.
    743          */
    744         public static final int REQUEST_TYPE_UPDATE = 4;
    745 
    746         /** @hide */
    747         @IntDef({
    748             REQUEST_TYPE_INITIAL,
    749             REQUEST_TYPE_RENEWAL,
    750             REQUEST_TYPE_RELEASE,
    751             REQUEST_TYPE_NONE,
    752             REQUEST_TYPE_UPDATE,
    753         })
    754         @Retention(RetentionPolicy.SOURCE)
    755         public @interface RequestType {}
    756 
    757         KeyRequest() {}
    758 
    759         /**
    760          * Get the opaque message data
    761          */
    762         @NonNull
    763         public byte[] getData() {
    764             if (mData == null) {
    765                 // this should never happen as mData is initialized in
    766                 // JNI after construction of the KeyRequest object. The check
    767                 // is needed here to guarantee @NonNull annotation.
    768                 throw new RuntimeException("KeyRequest is not initialized");
    769             }
    770             return mData;
    771         }
    772 
    773         /**
    774          * Get the default URL to use when sending the key request message to a
    775          * server, if known.  The app may prefer to use a different license
    776          * server URL from other sources.
    777          * This method returns an empty string if the default URL is not known.
    778          */
    779         @NonNull
    780         public String getDefaultUrl() {
    781             if (mDefaultUrl == null) {
    782                 // this should never happen as mDefaultUrl is initialized in
    783                 // JNI after construction of the KeyRequest object. The check
    784                 // is needed here to guarantee @NonNull annotation.
    785                 throw new RuntimeException("KeyRequest is not initialized");
    786             }
    787             return mDefaultUrl;
    788         }
    789 
    790         /**
    791          * Get the type of the request
    792          * @return one of {@link #REQUEST_TYPE_INITIAL},
    793          * {@link #REQUEST_TYPE_RENEWAL}, {@link #REQUEST_TYPE_RELEASE},
    794          * {@link #REQUEST_TYPE_NONE} or {@link #REQUEST_TYPE_UPDATE}
    795          */
    796         @RequestType
    797         public int getRequestType() { return mRequestType; }
    798     };
    799 
    800     /**
    801      * A key request/response exchange occurs between the app and a license server
    802      * to obtain or release keys used to decrypt encrypted content.
    803      * <p>
    804      * getKeyRequest() is used to obtain an opaque key request byte array that is
    805      * delivered to the license server.  The opaque key request byte array is returned
    806      * in KeyRequest.data.  The recommended URL to deliver the key request to is
    807      * returned in KeyRequest.defaultUrl.
    808      * <p>
    809      * After the app has received the key request response from the server,
    810      * it should deliver to the response to the MediaDrm instance using the method
    811      * {@link #provideKeyResponse}.
    812      *
    813      * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
    814      * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
    815      * scope should be set to the sessionId the keys will be provided to.  When the keyType
    816      * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
    817      * being released. Releasing keys from a device invalidates them for all sessions.
    818      * @param init container-specific data, its meaning is interpreted based on the
    819      * mime type provided in the mimeType parameter.  It could contain, for example,
    820      * the content ID, key ID or other data obtained from the content metadata that is
    821      * required in generating the key request. May be null when keyType is
    822      * KEY_TYPE_RELEASE or if the request is a renewal, i.e. not the first key
    823      * request for the session.
    824      * @param mimeType identifies the mime type of the content. May be null if the
    825      * keyType is KEY_TYPE_RELEASE or if the request is a renewal, i.e. not the
    826      * first key request for the session.
    827      * @param keyType specifes the type of the request. The request may be to acquire
    828      * keys for streaming or offline content, or to release previously acquired
    829      * keys, which are identified by a keySetId.
    830      * @param optionalParameters are included in the key request message to
    831      * allow a client application to provide additional message parameters to the server.
    832      * This may be {@code null} if no additional parameters are to be sent.
    833      * @throws NotProvisionedException if reprovisioning is needed, due to a
    834      * problem with the certifcate
    835      */
    836     @NonNull
    837     public native KeyRequest getKeyRequest(
    838             @NonNull byte[] scope, @Nullable byte[] init,
    839             @Nullable String mimeType, @KeyType int keyType,
    840             @Nullable HashMap<String, String> optionalParameters)
    841             throws NotProvisionedException;
    842 
    843 
    844     /**
    845      * A key response is received from the license server by the app, then it is
    846      * provided to the MediaDrm instance using provideKeyResponse.  When the
    847      * response is for an offline key request, a keySetId is returned that can be
    848      * used to later restore the keys to a new session with the method
    849      * {@link #restoreKeys}.
    850      * When the response is for a streaming or release request, an empty byte array
    851      * is returned.
    852      *
    853      * @param scope may be a sessionId or keySetId depending on the type of the
    854      * response.  Scope should be set to the sessionId when the response is for either
    855      * streaming or offline key requests.  Scope should be set to the keySetId when
    856      * the response is for a release request.
    857      * @param response the byte array response from the server
    858      * @return If the response is for an offline request, the keySetId for the offline
    859      * keys will be returned. If the response is for a streaming or release request
    860      * an empty byte array will be returned.
    861      *
    862      * @throws NotProvisionedException if the response indicates that
    863      * reprovisioning is required
    864      * @throws DeniedByServerException if the response indicates that the
    865      * server rejected the request
    866      */
    867     @Nullable
    868     public native byte[] provideKeyResponse(
    869             @NonNull byte[] scope, @NonNull byte[] response)
    870             throws NotProvisionedException, DeniedByServerException;
    871 
    872 
    873     /**
    874      * Restore persisted offline keys into a new session.  keySetId identifies the
    875      * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
    876      *
    877      * @param sessionId the session ID for the DRM session
    878      * @param keySetId identifies the saved key set to restore
    879      */
    880     public native void restoreKeys(@NonNull byte[] sessionId, @NonNull byte[] keySetId);
    881 
    882     /**
    883      * Remove the current keys from a session.
    884      *
    885      * @param sessionId the session ID for the DRM session
    886      */
    887     public native void removeKeys(@NonNull byte[] sessionId);
    888 
    889     /**
    890      * Request an informative description of the key status for the session.  The status is
    891      * in the form of {name, value} pairs.  Since DRM license policies vary by vendor,
    892      * the specific status field names are determined by each DRM vendor.  Refer to your
    893      * DRM provider documentation for definitions of the field names for a particular
    894      * DRM plugin.
    895      *
    896      * @param sessionId the session ID for the DRM session
    897      */
    898     @NonNull
    899     public native HashMap<String, String> queryKeyStatus(@NonNull byte[] sessionId);
    900 
    901     /**
    902      * Contains the opaque data an app uses to request a certificate from a provisioning
    903      * server
    904      */
    905     public static final class ProvisionRequest {
    906         ProvisionRequest() {}
    907 
    908         /**
    909          * Get the opaque message data
    910          */
    911         @NonNull
    912         public byte[] getData() {
    913             if (mData == null) {
    914                 // this should never happen as mData is initialized in
    915                 // JNI after construction of the KeyRequest object. The check
    916                 // is needed here to guarantee @NonNull annotation.
    917                 throw new RuntimeException("ProvisionRequest is not initialized");
    918             }
    919             return mData;
    920         }
    921 
    922         /**
    923          * Get the default URL to use when sending the provision request
    924          * message to a server, if known. The app may prefer to use a different
    925          * provisioning server URL obtained from other sources.
    926          * This method returns an empty string if the default URL is not known.
    927          */
    928         @NonNull
    929         public String getDefaultUrl() {
    930             if (mDefaultUrl == null) {
    931                 // this should never happen as mDefaultUrl is initialized in
    932                 // JNI after construction of the ProvisionRequest object. The check
    933                 // is needed here to guarantee @NonNull annotation.
    934                 throw new RuntimeException("ProvisionRequest is not initialized");
    935             }
    936             return mDefaultUrl;
    937         }
    938 
    939         private byte[] mData;
    940         private String mDefaultUrl;
    941     }
    942 
    943     /**
    944      * A provision request/response exchange occurs between the app and a provisioning
    945      * server to retrieve a device certificate.  If provisionining is required, the
    946      * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
    947      * getProvisionRequest is used to obtain the opaque provision request byte array that
    948      * should be delivered to the provisioning server. The provision request byte array
    949      * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
    950      * request to is returned in ProvisionRequest.defaultUrl.
    951      */
    952     @NonNull
    953     public ProvisionRequest getProvisionRequest() {
    954         return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
    955     }
    956 
    957     @NonNull
    958     private native ProvisionRequest getProvisionRequestNative(int certType,
    959            @NonNull String certAuthority);
    960 
    961     /**
    962      * After a provision response is received by the app, it is provided to the
    963      * MediaDrm instance using this method.
    964      *
    965      * @param response the opaque provisioning response byte array to provide to the
    966      * MediaDrm instance.
    967      *
    968      * @throws DeniedByServerException if the response indicates that the
    969      * server rejected the request
    970      */
    971     public void provideProvisionResponse(@NonNull byte[] response)
    972             throws DeniedByServerException {
    973         provideProvisionResponseNative(response);
    974     }
    975 
    976     @NonNull
    977     private native Certificate provideProvisionResponseNative(@NonNull byte[] response)
    978             throws DeniedByServerException;
    979 
    980     /**
    981      * Secure stops are a way to enforce limits on the number of concurrent
    982      * streams per subscriber across devices. They provide secure monitoring of
    983      * the lifetime of content decryption keys in MediaDrm sessions.
    984      * <p>
    985      * A secure stop is written to secure persistent memory when keys are loaded
    986      * into a MediaDrm session. The secure stop state indicates that the keys
    987      * are available for use. When playback completes and the keys are removed
    988      * or the session is destroyed, the secure stop state is updated to indicate
    989      * that keys are no longer usable.
    990      * <p>
    991      * After playback, the app can query the secure stop and send it in a
    992      * message to the license server confirming that the keys are no longer
    993      * active. The license server returns a secure stop release response
    994      * message to the app which then deletes the secure stop from persistent
    995      * memory using {@link #releaseSecureStops}.
    996      * <p>
    997      * Each secure stop has a unique ID that can be used to identify it during
    998      * enumeration, access and removal.
    999      * @return a list of all secure stops from secure persistent memory
   1000      */
   1001     @NonNull
   1002     public native List<byte[]> getSecureStops();
   1003 
   1004     /**
   1005      * Return a list of all secure stop IDs currently in persistent memory.
   1006      * The secure stop ID can be used to access or remove the corresponding
   1007      * secure stop.
   1008      *
   1009      * @return a list of secure stop IDs
   1010      */
   1011     @NonNull
   1012     public native List<byte[]> getSecureStopIds();
   1013 
   1014     /**
   1015      * Access a specific secure stop given its secure stop ID.
   1016      * Each secure stop has a unique ID.
   1017      *
   1018      * @param ssid the ID of the secure stop to return
   1019      * @return the secure stop identified by ssid
   1020      */
   1021     @NonNull
   1022     public native byte[] getSecureStop(@NonNull byte[] ssid);
   1023 
   1024     /**
   1025      * Process the secure stop server response message ssRelease.  After
   1026      * authenticating the message, remove the secure stops identified in the
   1027      * response.
   1028      *
   1029      * @param ssRelease the server response indicating which secure stops to release
   1030      */
   1031     public native void releaseSecureStops(@NonNull byte[] ssRelease);
   1032 
   1033     /**
   1034      * Remove a specific secure stop without requiring a secure stop release message
   1035      * from the license server.
   1036      * @param ssid the ID of the secure stop to remove
   1037      */
   1038     public native void removeSecureStop(@NonNull byte[] ssid);
   1039 
   1040     /**
   1041      * Remove all secure stops without requiring a secure stop release message from
   1042      * the license server.
   1043      *
   1044      * This method was added in API 28. In API versions 18 through 27,
   1045      * {@link #releaseAllSecureStops} should be called instead. There is no need to
   1046      * do anything for API versions prior to 18.
   1047      */
   1048     public native void removeAllSecureStops();
   1049 
   1050     /**
   1051      * Remove all secure stops without requiring a secure stop release message from
   1052      * the license server.
   1053      *
   1054      * @deprecated Remove all secure stops using {@link #removeAllSecureStops} instead.
   1055      */
   1056     public void releaseAllSecureStops() {
   1057         removeAllSecureStops();;
   1058     }
   1059 
   1060     @Retention(RetentionPolicy.SOURCE)
   1061     @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2,
   1062                         HDCP_V2_1, HDCP_V2_2, HDCP_NO_DIGITAL_OUTPUT})
   1063     public @interface HdcpLevel {}
   1064 
   1065 
   1066     /**
   1067      * The DRM plugin did not report an HDCP level, or an error
   1068      * occurred accessing it
   1069      */
   1070     public static final int HDCP_LEVEL_UNKNOWN = 0;
   1071 
   1072     /**
   1073      * HDCP is not supported on this device, content is unprotected
   1074      */
   1075     public static final int HDCP_NONE = 1;
   1076 
   1077     /**
   1078      * HDCP version 1.0
   1079      */
   1080     public static final int HDCP_V1 = 2;
   1081 
   1082     /**
   1083      * HDCP version 2.0 Type 1.
   1084      */
   1085     public static final int HDCP_V2 = 3;
   1086 
   1087     /**
   1088      * HDCP version 2.1 Type 1.
   1089      */
   1090     public static final int HDCP_V2_1 = 4;
   1091 
   1092     /**
   1093      *  HDCP version 2.2 Type 1.
   1094      */
   1095     public static final int HDCP_V2_2 = 5;
   1096 
   1097     /**
   1098      * No digital output, implicitly secure
   1099      */
   1100     public static final int HDCP_NO_DIGITAL_OUTPUT = Integer.MAX_VALUE;
   1101 
   1102     /**
   1103      * Return the HDCP level negotiated with downstream receivers the
   1104      * device is connected to. If multiple HDCP-capable displays are
   1105      * simultaneously connected to separate interfaces, this method
   1106      * returns the lowest negotiated level of all interfaces.
   1107      * <p>
   1108      * This method should only be used for informational purposes, not for
   1109      * enforcing compliance with HDCP requirements. Trusted enforcement of
   1110      * HDCP policies must be handled by the DRM system.
   1111      * <p>
   1112      * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE},
   1113      * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2}
   1114      * or {@link #HDCP_NO_DIGITAL_OUTPUT}.
   1115      */
   1116     @HdcpLevel
   1117     public native int getConnectedHdcpLevel();
   1118 
   1119     /**
   1120      * Return the maximum supported HDCP level. The maximum HDCP level is a
   1121      * constant for a given device, it does not depend on downstream receivers
   1122      * that may be connected. If multiple HDCP-capable interfaces are present,
   1123      * it indicates the highest of the maximum HDCP levels of all interfaces.
   1124      * <p>
   1125      * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE},
   1126      * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2}
   1127      * or {@link #HDCP_NO_DIGITAL_OUTPUT}.
   1128      */
   1129     @HdcpLevel
   1130     public native int getMaxHdcpLevel();
   1131 
   1132     /**
   1133      * Return the number of MediaDrm sessions that are currently opened
   1134      * simultaneously among all MediaDrm instances for the active DRM scheme.
   1135      * @return the number of open sessions.
   1136      */
   1137     public native int getOpenSessionCount();
   1138 
   1139     /**
   1140      * Return the maximum number of MediaDrm sessions that may be opened
   1141      * simultaneosly among all MediaDrm instances for the active DRM
   1142      * scheme. The maximum number of sessions is not affected by any
   1143      * sessions that may have already been opened.
   1144      * @return maximum sessions.
   1145      */
   1146     public native int getMaxSessionCount();
   1147 
   1148     /**
   1149      * Security level indicates the robustness of the device's DRM
   1150      * implementation.
   1151      */
   1152     @Retention(RetentionPolicy.SOURCE)
   1153     @IntDef({SECURITY_LEVEL_UNKNOWN, SECURITY_LEVEL_SW_SECURE_CRYPTO,
   1154             SECURITY_LEVEL_SW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_CRYPTO,
   1155             SECURITY_LEVEL_HW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_ALL})
   1156     public @interface SecurityLevel {}
   1157 
   1158     /**
   1159      * The DRM plugin did not report a security level, or an error occurred
   1160      * accessing it
   1161      */
   1162     public static final int SECURITY_LEVEL_UNKNOWN = 0;
   1163 
   1164     /**
   1165      * DRM key management uses software-based whitebox crypto.
   1166      */
   1167     public static final int SECURITY_LEVEL_SW_SECURE_CRYPTO = 1;
   1168 
   1169     /**
   1170      * DRM key management and decoding use software-based whitebox crypto.
   1171      */
   1172     public static final int SECURITY_LEVEL_SW_SECURE_DECODE = 2;
   1173 
   1174     /**
   1175      * DRM key management and crypto operations are performed within a hardware
   1176      * backed trusted execution environment.
   1177      */
   1178     public static final int SECURITY_LEVEL_HW_SECURE_CRYPTO = 3;
   1179 
   1180     /**
   1181      * DRM key management, crypto operations and decoding of content are
   1182      * performed within a hardware backed trusted execution environment.
   1183      */
   1184     public static final int SECURITY_LEVEL_HW_SECURE_DECODE = 4;
   1185 
   1186     /**
   1187      * DRM key management, crypto operations, decoding of content and all
   1188      * handling of the media (compressed and uncompressed) is handled within a
   1189      * hardware backed trusted execution environment.
   1190      */
   1191     public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5;
   1192 
   1193     /**
   1194      * The maximum security level supported by the device. This is the default
   1195      * security level when a session is opened.
   1196      * @hide
   1197      */
   1198     public static final int SECURITY_LEVEL_MAX = 6;
   1199 
   1200     /**
   1201      * The maximum security level supported by the device. This is the default
   1202      * security level when a session is opened.
   1203      */
   1204     @SecurityLevel
   1205     public static final int getMaxSecurityLevel() {
   1206         return SECURITY_LEVEL_MAX;
   1207     }
   1208 
   1209     /**
   1210      * Return the current security level of a session. A session has an initial
   1211      * security level determined by the robustness of the DRM system's
   1212      * implementation on the device. The security level may be changed at the
   1213      * time a session is opened using {@link #openSession}.
   1214      * @param sessionId the session to query.
   1215      * <p>
   1216      * @return one of {@link #SECURITY_LEVEL_UNKNOWN},
   1217      * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
   1218      * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or
   1219      * {@link #SECURITY_LEVEL_HW_SECURE_ALL}.
   1220      */
   1221     @SecurityLevel
   1222     public native int getSecurityLevel(@NonNull byte[] sessionId);
   1223 
   1224     /**
   1225      * String property name: identifies the maker of the DRM plugin
   1226      */
   1227     public static final String PROPERTY_VENDOR = "vendor";
   1228 
   1229     /**
   1230      * String property name: identifies the version of the DRM plugin
   1231      */
   1232     public static final String PROPERTY_VERSION = "version";
   1233 
   1234     /**
   1235      * String property name: describes the DRM plugin
   1236      */
   1237     public static final String PROPERTY_DESCRIPTION = "description";
   1238 
   1239     /**
   1240      * String property name: a comma-separated list of cipher and mac algorithms
   1241      * supported by CryptoSession.  The list may be empty if the DRM
   1242      * plugin does not support CryptoSession operations.
   1243      */
   1244     public static final String PROPERTY_ALGORITHMS = "algorithms";
   1245 
   1246     /** @hide */
   1247     @StringDef(prefix = { "PROPERTY_" }, value = {
   1248         PROPERTY_VENDOR,
   1249         PROPERTY_VERSION,
   1250         PROPERTY_DESCRIPTION,
   1251         PROPERTY_ALGORITHMS,
   1252     })
   1253     @Retention(RetentionPolicy.SOURCE)
   1254     public @interface StringProperty {}
   1255 
   1256     /**
   1257      * Read a MediaDrm String property value, given the property name string.
   1258      * <p>
   1259      * Standard fields names are:
   1260      * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
   1261      * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
   1262      */
   1263     @NonNull
   1264     public native String getPropertyString(@NonNull @StringProperty String propertyName);
   1265 
   1266     /**
   1267      * Set a MediaDrm String property value, given the property name string
   1268      * and new value for the property.
   1269      */
   1270     public native void setPropertyString(@NonNull @StringProperty String propertyName,
   1271             @NonNull String value);
   1272 
   1273     /**
   1274      * Byte array property name: the device unique identifier is established during
   1275      * device provisioning and provides a means of uniquely identifying each device.
   1276      */
   1277     public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
   1278 
   1279     /** @hide */
   1280     @StringDef(prefix = { "PROPERTY_" }, value = {
   1281         PROPERTY_DEVICE_UNIQUE_ID,
   1282     })
   1283     @Retention(RetentionPolicy.SOURCE)
   1284     public @interface ArrayProperty {}
   1285 
   1286     /**
   1287      * Read a MediaDrm byte array property value, given the property name string.
   1288      * <p>
   1289      * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
   1290      */
   1291     @NonNull
   1292     public native byte[] getPropertyByteArray(@ArrayProperty String propertyName);
   1293 
   1294     /**
   1295     * Set a MediaDrm byte array property value, given the property name string
   1296     * and new value for the property.
   1297     */
   1298     public native void setPropertyByteArray(@NonNull @ArrayProperty
   1299             String propertyName, @NonNull byte[] value);
   1300 
   1301     private static final native void setCipherAlgorithmNative(
   1302             @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
   1303 
   1304     private static final native void setMacAlgorithmNative(
   1305             @NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
   1306 
   1307     @NonNull
   1308     private static final native byte[] encryptNative(
   1309             @NonNull MediaDrm drm, @NonNull byte[] sessionId,
   1310             @NonNull byte[] keyId, @NonNull byte[] input, @NonNull byte[] iv);
   1311 
   1312     @NonNull
   1313     private static final native byte[] decryptNative(
   1314             @NonNull MediaDrm drm, @NonNull byte[] sessionId,
   1315             @NonNull byte[] keyId, @NonNull byte[] input, @NonNull byte[] iv);
   1316 
   1317     @NonNull
   1318     private static final native byte[] signNative(
   1319             @NonNull MediaDrm drm, @NonNull byte[] sessionId,
   1320             @NonNull byte[] keyId, @NonNull byte[] message);
   1321 
   1322     private static final native boolean verifyNative(
   1323             @NonNull MediaDrm drm, @NonNull byte[] sessionId,
   1324             @NonNull byte[] keyId, @NonNull byte[] message, @NonNull byte[] signature);
   1325 
   1326     /**
   1327      * Return Metrics data about the current MediaDrm instance.
   1328      *
   1329      * @return a {@link PersistableBundle} containing the set of attributes and values
   1330      * available for this instance of MediaDrm.
   1331      * The attributes are described in {@link MetricsConstants}.
   1332      *
   1333      * Additional vendor-specific fields may also be present in
   1334      * the return value.
   1335      */
   1336     public PersistableBundle getMetrics() {
   1337         PersistableBundle bundle = getMetricsNative();
   1338         return bundle;
   1339     }
   1340 
   1341     private native PersistableBundle getMetricsNative();
   1342 
   1343     /**
   1344      * In addition to supporting decryption of DASH Common Encrypted Media, the
   1345      * MediaDrm APIs provide the ability to securely deliver session keys from
   1346      * an operator's session key server to a client device, based on the factory-installed
   1347      * root of trust, and then perform encrypt, decrypt, sign and verify operations
   1348      * with the session key on arbitrary user data.
   1349      * <p>
   1350      * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
   1351      * based on the established session keys.  These keys are exchanged using the
   1352      * getKeyRequest/provideKeyResponse methods.
   1353      * <p>
   1354      * Applications of this capability could include securing various types of
   1355      * purchased or private content, such as applications, books and other media,
   1356      * photos or media delivery protocols.
   1357      * <p>
   1358      * Operators can create session key servers that are functionally similar to a
   1359      * license key server, except that instead of receiving license key requests and
   1360      * providing encrypted content keys which are used specifically to decrypt A/V media
   1361      * content, the session key server receives session key requests and provides
   1362      * encrypted session keys which can be used for general purpose crypto operations.
   1363      * <p>
   1364      * A CryptoSession is obtained using {@link #getCryptoSession}
   1365      */
   1366     public final class CryptoSession {
   1367         private byte[] mSessionId;
   1368 
   1369         CryptoSession(@NonNull byte[] sessionId,
   1370                       @NonNull String cipherAlgorithm,
   1371                       @NonNull String macAlgorithm)
   1372         {
   1373             mSessionId = sessionId;
   1374             setCipherAlgorithmNative(MediaDrm.this, sessionId, cipherAlgorithm);
   1375             setMacAlgorithmNative(MediaDrm.this, sessionId, macAlgorithm);
   1376         }
   1377 
   1378         /**
   1379          * Encrypt data using the CryptoSession's cipher algorithm
   1380          *
   1381          * @param keyid specifies which key to use
   1382          * @param input the data to encrypt
   1383          * @param iv the initialization vector to use for the cipher
   1384          */
   1385         @NonNull
   1386         public byte[] encrypt(
   1387                 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) {
   1388             return encryptNative(MediaDrm.this, mSessionId, keyid, input, iv);
   1389         }
   1390 
   1391         /**
   1392          * Decrypt data using the CryptoSessions's cipher algorithm
   1393          *
   1394          * @param keyid specifies which key to use
   1395          * @param input the data to encrypt
   1396          * @param iv the initialization vector to use for the cipher
   1397          */
   1398         @NonNull
   1399         public byte[] decrypt(
   1400                 @NonNull byte[] keyid, @NonNull byte[] input, @NonNull byte[] iv) {
   1401             return decryptNative(MediaDrm.this, mSessionId, keyid, input, iv);
   1402         }
   1403 
   1404         /**
   1405          * Sign data using the CryptoSessions's mac algorithm.
   1406          *
   1407          * @param keyid specifies which key to use
   1408          * @param message the data for which a signature is to be computed
   1409          */
   1410         @NonNull
   1411         public byte[] sign(@NonNull byte[] keyid, @NonNull byte[] message) {
   1412             return signNative(MediaDrm.this, mSessionId, keyid, message);
   1413         }
   1414 
   1415         /**
   1416          * Verify a signature using the CryptoSessions's mac algorithm. Return true
   1417          * if the signatures match, false if they do no.
   1418          *
   1419          * @param keyid specifies which key to use
   1420          * @param message the data to verify
   1421          * @param signature the reference signature which will be compared with the
   1422          *        computed signature
   1423          */
   1424         public boolean verify(
   1425                 @NonNull byte[] keyid, @NonNull byte[] message, @NonNull byte[] signature) {
   1426             return verifyNative(MediaDrm.this, mSessionId, keyid, message, signature);
   1427         }
   1428     };
   1429 
   1430     /**
   1431      * Obtain a CryptoSession object which can be used to encrypt, decrypt,
   1432      * sign and verify messages or data using the session keys established
   1433      * for the session using methods {@link #getKeyRequest} and
   1434      * {@link #provideKeyResponse} using a session key server.
   1435      *
   1436      * @param sessionId the session ID for the session containing keys
   1437      * to be used for encrypt, decrypt, sign and/or verify
   1438      * @param cipherAlgorithm the algorithm to use for encryption and
   1439      * decryption ciphers. The algorithm string conforms to JCA Standard
   1440      * Names for Cipher Transforms and is case insensitive.  For example
   1441      * "AES/CBC/NoPadding".
   1442      * @param macAlgorithm the algorithm to use for sign and verify
   1443      * The algorithm string conforms to JCA Standard Names for Mac
   1444      * Algorithms and is case insensitive.  For example "HmacSHA256".
   1445      * <p>
   1446      * The list of supported algorithms for a DRM plugin can be obtained
   1447      * using the method {@link #getPropertyString} with the property name
   1448      * "algorithms".
   1449      */
   1450     public CryptoSession getCryptoSession(
   1451             @NonNull byte[] sessionId,
   1452             @NonNull String cipherAlgorithm, @NonNull String macAlgorithm)
   1453     {
   1454         return new CryptoSession(sessionId, cipherAlgorithm, macAlgorithm);
   1455     }
   1456 
   1457     /**
   1458      * Contains the opaque data an app uses to request a certificate from a provisioning
   1459      * server
   1460      *
   1461      * @hide - not part of the public API at this time
   1462      */
   1463     public static final class CertificateRequest {
   1464         private byte[] mData;
   1465         private String mDefaultUrl;
   1466 
   1467         CertificateRequest(@NonNull byte[] data, @NonNull String defaultUrl) {
   1468             mData = data;
   1469             mDefaultUrl = defaultUrl;
   1470         }
   1471 
   1472         /**
   1473          * Get the opaque message data
   1474          */
   1475         @NonNull
   1476         public byte[] getData() { return mData; }
   1477 
   1478         /**
   1479          * Get the default URL to use when sending the certificate request
   1480          * message to a server, if known. The app may prefer to use a different
   1481          * certificate server URL obtained from other sources.
   1482          */
   1483         @NonNull
   1484         public String getDefaultUrl() { return mDefaultUrl; }
   1485     }
   1486 
   1487     /**
   1488      * Generate a certificate request, specifying the certificate type
   1489      * and authority. The response received should be passed to
   1490      * provideCertificateResponse.
   1491      *
   1492      * @param certType Specifies the certificate type.
   1493      *
   1494      * @param certAuthority is passed to the certificate server to specify
   1495      * the chain of authority.
   1496      *
   1497      * @hide - not part of the public API at this time
   1498      */
   1499     @NonNull
   1500     public CertificateRequest getCertificateRequest(
   1501             @CertificateType int certType, @NonNull String certAuthority)
   1502     {
   1503         ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
   1504         return new CertificateRequest(provisionRequest.getData(),
   1505                 provisionRequest.getDefaultUrl());
   1506     }
   1507 
   1508     /**
   1509      * Contains the wrapped private key and public certificate data associated
   1510      * with a certificate.
   1511      *
   1512      * @hide - not part of the public API at this time
   1513      */
   1514     public static final class Certificate {
   1515         Certificate() {}
   1516 
   1517         /**
   1518          * Get the wrapped private key data
   1519          */
   1520         @NonNull
   1521         public byte[] getWrappedPrivateKey() {
   1522             if (mWrappedKey == null) {
   1523                 // this should never happen as mWrappedKey is initialized in
   1524                 // JNI after construction of the KeyRequest object. The check
   1525                 // is needed here to guarantee @NonNull annotation.
   1526                 throw new RuntimeException("Cerfificate is not initialized");
   1527             }
   1528             return mWrappedKey;
   1529         }
   1530 
   1531         /**
   1532          * Get the PEM-encoded certificate chain
   1533          */
   1534         @NonNull
   1535         public byte[] getContent() {
   1536             if (mCertificateData == null) {
   1537                 // this should never happen as mCertificateData is initialized in
   1538                 // JNI after construction of the KeyRequest object. The check
   1539                 // is needed here to guarantee @NonNull annotation.
   1540                 throw new RuntimeException("Cerfificate is not initialized");
   1541             }
   1542             return mCertificateData;
   1543         }
   1544 
   1545         private byte[] mWrappedKey;
   1546         private byte[] mCertificateData;
   1547     }
   1548 
   1549 
   1550     /**
   1551      * Process a response from the certificate server.  The response
   1552      * is obtained from an HTTP Post to the url provided by getCertificateRequest.
   1553      * <p>
   1554      * The public X509 certificate chain and wrapped private key are returned
   1555      * in the returned Certificate objec.  The certificate chain is in PEM format.
   1556      * The wrapped private key should be stored in application private
   1557      * storage, and used when invoking the signRSA method.
   1558      *
   1559      * @param response the opaque certificate response byte array to provide to the
   1560      * MediaDrm instance.
   1561      *
   1562      * @throws DeniedByServerException if the response indicates that the
   1563      * server rejected the request
   1564      *
   1565      * @hide - not part of the public API at this time
   1566      */
   1567     @NonNull
   1568     public Certificate provideCertificateResponse(@NonNull byte[] response)
   1569             throws DeniedByServerException {
   1570         return provideProvisionResponseNative(response);
   1571     }
   1572 
   1573     @NonNull
   1574     private static final native byte[] signRSANative(
   1575             @NonNull MediaDrm drm, @NonNull byte[] sessionId,
   1576             @NonNull String algorithm, @NonNull byte[] wrappedKey, @NonNull byte[] message);
   1577 
   1578     /**
   1579      * Sign data using an RSA key
   1580      *
   1581      * @param sessionId a sessionId obtained from openSession on the MediaDrm object
   1582      * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
   1583      * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
   1584      * from provideCertificateResponse
   1585      * @param message the data for which a signature is to be computed
   1586      *
   1587      * @hide - not part of the public API at this time
   1588      */
   1589     @NonNull
   1590     public byte[] signRSA(
   1591             @NonNull byte[] sessionId, @NonNull String algorithm,
   1592             @NonNull byte[] wrappedKey, @NonNull byte[] message) {
   1593         return signRSANative(this, sessionId, algorithm, wrappedKey, message);
   1594     }
   1595 
   1596     @Override
   1597     protected void finalize() throws Throwable {
   1598         try {
   1599             if (mCloseGuard != null) {
   1600                 mCloseGuard.warnIfOpen();
   1601             }
   1602             release();
   1603         } finally {
   1604             super.finalize();
   1605         }
   1606     }
   1607 
   1608     /**
   1609      * Releases resources associated with the current session of
   1610      * MediaDrm. It is considered good practice to call this method when
   1611      * the {@link MediaDrm} object is no longer needed in your
   1612      * application. After this method is called, {@link MediaDrm} is no
   1613      * longer usable since it has lost all of its required resource.
   1614      *
   1615      * This method was added in API 28. In API versions 18 through 27, release()
   1616      * should be called instead. There is no need to do anything for API
   1617      * versions prior to 18.
   1618      */
   1619     @Override
   1620     public void close() {
   1621         release();
   1622     }
   1623 
   1624     /**
   1625      * @deprecated replaced by {@link #close()}.
   1626      */
   1627     @Deprecated
   1628     public void release() {
   1629         mCloseGuard.close();
   1630         if (mClosed.compareAndSet(false, true)) {
   1631             native_release();
   1632         }
   1633     }
   1634 
   1635     /** @hide */
   1636     public native final void native_release();
   1637 
   1638     private static native final void native_init();
   1639 
   1640     private native final void native_setup(Object mediadrm_this, byte[] uuid,
   1641             String appPackageName);
   1642 
   1643     static {
   1644         System.loadLibrary("media_jni");
   1645         native_init();
   1646     }
   1647 
   1648     /**
   1649      * Definitions for the metrics that are reported via the
   1650      * {@link #getMetrics} call.
   1651      */
   1652     public final static class MetricsConstants
   1653     {
   1654         private MetricsConstants() {}
   1655 
   1656         /**
   1657          * Key to extract the number of successful {@link #openSession} calls
   1658          * from the {@link PersistableBundle} returned by a
   1659          * {@link #getMetrics} call.
   1660          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1661          */
   1662         public static final String OPEN_SESSION_OK_COUNT
   1663             = "drm.mediadrm.open_session.ok.count";
   1664 
   1665         /**
   1666          * Key to extract the number of failed {@link #openSession} calls
   1667          * from the {@link PersistableBundle} returned by a
   1668          * {@link #getMetrics} call.
   1669          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1670          */
   1671         public static final String OPEN_SESSION_ERROR_COUNT
   1672             = "drm.mediadrm.open_session.error.count";
   1673 
   1674         /**
   1675          * Key to extract the list of error codes that were returned from
   1676          * {@link #openSession} calls. The key is used to lookup the list
   1677          * in the {@link PersistableBundle} returned by a {@link #getMetrics}
   1678          * call.
   1679          * The list is an array of Long values
   1680          * ({@link android.os.BaseBundle#getLongArray}).
   1681          */
   1682         public static final String OPEN_SESSION_ERROR_LIST
   1683             = "drm.mediadrm.open_session.error.list";
   1684 
   1685         /**
   1686          * Key to extract the number of successful {@link #closeSession} calls
   1687          * from the {@link PersistableBundle} returned by a
   1688          * {@link #getMetrics} call.
   1689          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1690          */
   1691         public static final String CLOSE_SESSION_OK_COUNT
   1692             = "drm.mediadrm.close_session.ok.count";
   1693 
   1694         /**
   1695          * Key to extract the number of failed {@link #closeSession} calls
   1696          * from the {@link PersistableBundle} returned by a
   1697          * {@link #getMetrics} call.
   1698          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1699          */
   1700         public static final String CLOSE_SESSION_ERROR_COUNT
   1701             = "drm.mediadrm.close_session.error.count";
   1702 
   1703         /**
   1704          * Key to extract the list of error codes that were returned from
   1705          * {@link #closeSession} calls. The key is used to lookup the list
   1706          * in the {@link PersistableBundle} returned by a {@link #getMetrics}
   1707          * call.
   1708          * The list is an array of Long values
   1709          * ({@link android.os.BaseBundle#getLongArray}).
   1710          */
   1711         public static final String CLOSE_SESSION_ERROR_LIST
   1712             = "drm.mediadrm.close_session.error.list";
   1713 
   1714         /**
   1715          * Key to extract the start times of sessions. Times are
   1716          * represented as milliseconds since epoch (1970-01-01T00:00:00Z).
   1717          * The start times are returned from the {@link PersistableBundle}
   1718          * from a {@link #getMetrics} call.
   1719          * The start times are returned as another {@link PersistableBundle}
   1720          * containing the session ids as keys and the start times as long
   1721          * values. Use {@link android.os.BaseBundle#keySet} to get the list of
   1722          * session ids, and then {@link android.os.BaseBundle#getLong} to get
   1723          * the start time for each session.
   1724          */
   1725         public static final String SESSION_START_TIMES_MS
   1726             = "drm.mediadrm.session_start_times_ms";
   1727 
   1728         /**
   1729          * Key to extract the end times of sessions. Times are
   1730          * represented as milliseconds since epoch (1970-01-01T00:00:00Z).
   1731          * The end times are returned from the {@link PersistableBundle}
   1732          * from a {@link #getMetrics} call.
   1733          * The end times are returned as another {@link PersistableBundle}
   1734          * containing the session ids as keys and the end times as long
   1735          * values. Use {@link android.os.BaseBundle#keySet} to get the list of
   1736          * session ids, and then {@link android.os.BaseBundle#getLong} to get
   1737          * the end time for each session.
   1738          */
   1739         public static final String SESSION_END_TIMES_MS
   1740             = "drm.mediadrm.session_end_times_ms";
   1741 
   1742         /**
   1743          * Key to extract the number of successful {@link #getKeyRequest} calls
   1744          * from the {@link PersistableBundle} returned by a
   1745          * {@link #getMetrics} call.
   1746          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1747          */
   1748         public static final String GET_KEY_REQUEST_OK_COUNT
   1749             = "drm.mediadrm.get_key_request.ok.count";
   1750 
   1751         /**
   1752          * Key to extract the number of failed {@link #getKeyRequest}
   1753          * calls from the {@link PersistableBundle} returned by a
   1754          * {@link #getMetrics} call.
   1755          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1756          */
   1757         public static final String GET_KEY_REQUEST_ERROR_COUNT
   1758             = "drm.mediadrm.get_key_request.error.count";
   1759 
   1760         /**
   1761          * Key to extract the list of error codes that were returned from
   1762          * {@link #getKeyRequest} calls. The key is used to lookup the list
   1763          * in the {@link PersistableBundle} returned by a {@link #getMetrics}
   1764          * call.
   1765          * The list is an array of Long values
   1766          * ({@link android.os.BaseBundle#getLongArray}).
   1767          */
   1768         public static final String GET_KEY_REQUEST_ERROR_LIST
   1769             = "drm.mediadrm.get_key_request.error.list";
   1770 
   1771         /**
   1772          * Key to extract the average time in microseconds of calls to
   1773          * {@link #getKeyRequest}. The value is retrieved from the
   1774          * {@link PersistableBundle} returned from {@link #getMetrics}.
   1775          * The time is a Long value ({@link android.os.BaseBundle#getLong}).
   1776          */
   1777         public static final String GET_KEY_REQUEST_OK_TIME_MICROS
   1778             = "drm.mediadrm.get_key_request.ok.average_time_micros";
   1779 
   1780         /**
   1781          * Key to extract the number of successful {@link #provideKeyResponse}
   1782          * calls from the {@link PersistableBundle} returned by a
   1783          * {@link #getMetrics} call.
   1784          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1785          */
   1786         public static final String PROVIDE_KEY_RESPONSE_OK_COUNT
   1787             = "drm.mediadrm.provide_key_response.ok.count";
   1788 
   1789         /**
   1790          * Key to extract the number of failed {@link #provideKeyResponse}
   1791          * calls from the {@link PersistableBundle} returned by a
   1792          * {@link #getMetrics} call.
   1793          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1794          */
   1795         public static final String PROVIDE_KEY_RESPONSE_ERROR_COUNT
   1796             = "drm.mediadrm.provide_key_response.error.count";
   1797 
   1798         /**
   1799          * Key to extract the list of error codes that were returned from
   1800          * {@link #provideKeyResponse} calls. The key is used to lookup the
   1801          * list in the {@link PersistableBundle} returned by a
   1802          * {@link #getMetrics} call.
   1803          * The list is an array of Long values
   1804          * ({@link android.os.BaseBundle#getLongArray}).
   1805          */
   1806         public static final String PROVIDE_KEY_RESPONSE_ERROR_LIST
   1807             = "drm.mediadrm.provide_key_response.error.list";
   1808 
   1809         /**
   1810          * Key to extract the average time in microseconds of calls to
   1811          * {@link #provideKeyResponse}. The valus is retrieved from the
   1812          * {@link PersistableBundle} returned from {@link #getMetrics}.
   1813          * The time is a Long value ({@link android.os.BaseBundle#getLong}).
   1814          */
   1815         public static final String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS
   1816             = "drm.mediadrm.provide_key_response.ok.average_time_micros";
   1817 
   1818         /**
   1819          * Key to extract the number of successful {@link #getProvisionRequest}
   1820          * calls from the {@link PersistableBundle} returned by a
   1821          * {@link #getMetrics} call.
   1822          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1823          */
   1824         public static final String GET_PROVISION_REQUEST_OK_COUNT
   1825             = "drm.mediadrm.get_provision_request.ok.count";
   1826 
   1827         /**
   1828          * Key to extract the number of failed {@link #getProvisionRequest}
   1829          * calls from the {@link PersistableBundle} returned by a
   1830          * {@link #getMetrics} call.
   1831          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1832          */
   1833         public static final String GET_PROVISION_REQUEST_ERROR_COUNT
   1834             = "drm.mediadrm.get_provision_request.error.count";
   1835 
   1836         /**
   1837          * Key to extract the list of error codes that were returned from
   1838          * {@link #getProvisionRequest} calls. The key is used to lookup the
   1839          * list in the {@link PersistableBundle} returned by a
   1840          * {@link #getMetrics} call.
   1841          * The list is an array of Long values
   1842          * ({@link android.os.BaseBundle#getLongArray}).
   1843          */
   1844         public static final String GET_PROVISION_REQUEST_ERROR_LIST
   1845             = "drm.mediadrm.get_provision_request.error.list";
   1846 
   1847         /**
   1848          * Key to extract the number of successful
   1849          * {@link #provideProvisionResponse} calls from the
   1850          * {@link PersistableBundle} returned by a {@link #getMetrics} call.
   1851          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1852          */
   1853         public static final String PROVIDE_PROVISION_RESPONSE_OK_COUNT
   1854             = "drm.mediadrm.provide_provision_response.ok.count";
   1855 
   1856         /**
   1857          * Key to extract the number of failed
   1858          * {@link #provideProvisionResponse} calls from the
   1859          * {@link PersistableBundle} returned by a {@link #getMetrics} call.
   1860          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1861          */
   1862         public static final String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT
   1863             = "drm.mediadrm.provide_provision_response.error.count";
   1864 
   1865         /**
   1866          * Key to extract the list of error codes that were returned from
   1867          * {@link #provideProvisionResponse} calls. The key is used to lookup
   1868          * the list in the {@link PersistableBundle} returned by a
   1869          * {@link #getMetrics} call.
   1870          * The list is an array of Long values
   1871          * ({@link android.os.BaseBundle#getLongArray}).
   1872          */
   1873         public static final String PROVIDE_PROVISION_RESPONSE_ERROR_LIST
   1874             = "drm.mediadrm.provide_provision_response.error.list";
   1875 
   1876         /**
   1877          * Key to extract the number of successful
   1878          * {@link #getPropertyByteArray} calls were made with the
   1879          * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup
   1880          * the value in the {@link PersistableBundle} returned by a
   1881          * {@link #getMetrics} call.
   1882          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1883          */
   1884         public static final String GET_DEVICE_UNIQUE_ID_OK_COUNT
   1885             = "drm.mediadrm.get_device_unique_id.ok.count";
   1886 
   1887         /**
   1888          * Key to extract the number of failed
   1889          * {@link #getPropertyByteArray} calls were made with the
   1890          * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup
   1891          * the value in the {@link PersistableBundle} returned by a
   1892          * {@link #getMetrics} call.
   1893          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1894          */
   1895         public static final String GET_DEVICE_UNIQUE_ID_ERROR_COUNT
   1896             = "drm.mediadrm.get_device_unique_id.error.count";
   1897 
   1898         /**
   1899          * Key to extract the list of error codes that were returned from
   1900          * {@link #getPropertyByteArray} calls with the
   1901          * {@link #PROPERTY_DEVICE_UNIQUE_ID} value. The key is used to lookup
   1902          * the list in the {@link PersistableBundle} returned by a
   1903          * {@link #getMetrics} call.
   1904          * The list is an array of Long values
   1905          * ({@link android.os.BaseBundle#getLongArray}).
   1906          */
   1907         public static final String GET_DEVICE_UNIQUE_ID_ERROR_LIST
   1908             = "drm.mediadrm.get_device_unique_id.error.list";
   1909 
   1910         /**
   1911          * Key to extraact the count of {@link KeyStatus#STATUS_EXPIRED} events
   1912          * that occured. The count is extracted from the
   1913          * {@link PersistableBundle} returned from a {@link #getMetrics} call.
   1914          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1915          */
   1916         public static final String KEY_STATUS_EXPIRED_COUNT
   1917             = "drm.mediadrm.key_status.EXPIRED.count";
   1918 
   1919         /**
   1920          * Key to extract the count of {@link KeyStatus#STATUS_INTERNAL_ERROR}
   1921          * events that occured. The count is extracted from the
   1922          * {@link PersistableBundle} returned from a {@link #getMetrics} call.
   1923          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1924          */
   1925         public static final String KEY_STATUS_INTERNAL_ERROR_COUNT
   1926             = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
   1927 
   1928         /**
   1929          * Key to extract the count of
   1930          * {@link KeyStatus#STATUS_OUTPUT_NOT_ALLOWED} events that occured.
   1931          * The count is extracted from the
   1932          * {@link PersistableBundle} returned from a {@link #getMetrics} call.
   1933          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1934          */
   1935         public static final String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT
   1936             = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
   1937 
   1938         /**
   1939          * Key to extract the count of {@link KeyStatus#STATUS_PENDING}
   1940          * events that occured. The count is extracted from the
   1941          * {@link PersistableBundle} returned from a {@link #getMetrics} call.
   1942          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1943          */
   1944         public static final String KEY_STATUS_PENDING_COUNT
   1945             = "drm.mediadrm.key_status_change.PENDING.count";
   1946 
   1947         /**
   1948          * Key to extract the count of {@link KeyStatus#STATUS_USABLE}
   1949          * events that occured. The count is extracted from the
   1950          * {@link PersistableBundle} returned from a {@link #getMetrics} call.
   1951          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1952          */
   1953         public static final String KEY_STATUS_USABLE_COUNT
   1954             = "drm.mediadrm.key_status_change.USABLE.count";
   1955 
   1956         /**
   1957          * Key to extract the count of {@link OnEventListener#onEvent}
   1958          * calls of type PROVISION_REQUIRED occured. The count is
   1959          * extracted from the {@link PersistableBundle} returned from a
   1960          * {@link #getMetrics} call.
   1961          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1962          */
   1963         public static final String EVENT_PROVISION_REQUIRED_COUNT
   1964             = "drm.mediadrm.event.PROVISION_REQUIRED.count";
   1965 
   1966         /**
   1967          * Key to extract the count of {@link OnEventListener#onEvent}
   1968          * calls of type KEY_NEEDED occured. The count is
   1969          * extracted from the {@link PersistableBundle} returned from a
   1970          * {@link #getMetrics} call.
   1971          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1972          */
   1973         public static final String EVENT_KEY_NEEDED_COUNT
   1974             = "drm.mediadrm.event.KEY_NEEDED.count";
   1975 
   1976         /**
   1977          * Key to extract the count of {@link OnEventListener#onEvent}
   1978          * calls of type KEY_EXPIRED occured. The count is
   1979          * extracted from the {@link PersistableBundle} returned from a
   1980          * {@link #getMetrics} call.
   1981          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1982          */
   1983         public static final String EVENT_KEY_EXPIRED_COUNT
   1984             = "drm.mediadrm.event.KEY_EXPIRED.count";
   1985 
   1986         /**
   1987          * Key to extract the count of {@link OnEventListener#onEvent}
   1988          * calls of type VENDOR_DEFINED. The count is
   1989          * extracted from the {@link PersistableBundle} returned from a
   1990          * {@link #getMetrics} call.
   1991          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   1992          */
   1993         public static final String EVENT_VENDOR_DEFINED_COUNT
   1994             = "drm.mediadrm.event.VENDOR_DEFINED.count";
   1995 
   1996         /**
   1997          * Key to extract the count of {@link OnEventListener#onEvent}
   1998          * calls of type SESSION_RECLAIMED. The count is
   1999          * extracted from the {@link PersistableBundle} returned from a
   2000          * {@link #getMetrics} call.
   2001          * The count is a Long value ({@link android.os.BaseBundle#getLong}).
   2002          */
   2003         public static final String EVENT_SESSION_RECLAIMED_COUNT
   2004             = "drm.mediadrm.event.SESSION_RECLAIMED.count";
   2005     }
   2006 }
   2007