diff options
Diffstat (limited to 'media')
50 files changed, 1529 insertions, 331 deletions
diff --git a/media/Android.bp b/media/Android.bp index 8b06bb26fcf7..9268b22a929a 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + aidl_interface { name: "audio_common-aidl", unstable: true, diff --git a/media/OWNERS b/media/OWNERS index e74149019b11..abfc8bfa976e 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -26,3 +26,7 @@ olly@google.com # SEO sungsoo@google.com + +# SEA/KIR/BVE +jtinker@google.com +robertshih@google.com diff --git a/media/java/Android.bp b/media/java/Android.bp index 0810699abf0a..aea63a073e95 100644 --- a/media/java/Android.bp +++ b/media/java/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "IMidiDeviceServer.aidl", srcs: ["android/media/midi/IMidiDeviceServer.aidl"], diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 205c1f4b4057..383c93d7716d 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -16,8 +16,10 @@ package android.media; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.util.SparseIntArray; import java.lang.annotation.Retention; @@ -161,6 +163,14 @@ public final class AudioDeviceInfo { */ public static final int TYPE_BLE_SPEAKER = 27; + /** + * A device type describing an Echo Canceller loopback Reference. + * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE, + * which requires privileged permission + * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}. + * @hide */ + @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_OUTPUT) + public static final int TYPE_ECHO_REFERENCE = 28; /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { @@ -188,7 +198,8 @@ public final class AudioDeviceInfo { TYPE_FM_TUNER, TYPE_TV_TUNER, TYPE_BLE_HEADSET, - TYPE_BLE_SPEAKER} + TYPE_BLE_SPEAKER, + TYPE_ECHO_REFERENCE} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceType {} @@ -211,7 +222,8 @@ public final class AudioDeviceInfo { TYPE_LINE_DIGITAL, TYPE_IP, TYPE_BUS, - TYPE_BLE_HEADSET} + TYPE_BLE_HEADSET, + TYPE_ECHO_REFERENCE} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeIn {} @@ -297,6 +309,7 @@ public final class AudioDeviceInfo { case TYPE_BUS: case TYPE_REMOTE_SUBMIX: case TYPE_BLE_HEADSET: + case TYPE_ECHO_REFERENCE: return true; default: return false; @@ -621,6 +634,8 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLE_HEADSET, TYPE_BLE_HEADSET); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ECHO_REFERENCE, TYPE_ECHO_REFERENCE); + // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); @@ -678,6 +693,9 @@ public final class AudioDeviceInfo { EXT_TO_INT_INPUT_DEVICE_MAPPING.put( TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX); EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET); + EXT_TO_INT_INPUT_DEVICE_MAPPING.put( + TYPE_ECHO_REFERENCE, AudioSystem.DEVICE_IN_ECHO_REFERENCE); + } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index d896c1fc82b5..f87f90d8e0a2 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -3123,52 +3123,57 @@ public class AudioManager { /** * @hide Home sound - * Played by the framework when the home app becomes active if config_enableHomeSound is set to - * true. This is currently only used on TV devices. + * <p> + * To be played by the framework when the home app becomes active if config_enableHomeSound is + * set to true. This is currently only used on TV devices. * Note that this sound is only available if a sound file is specified in audio_assets.xml. * @see #playSoundEffect(int) */ public static final int FX_HOME = 11; /** - * @hide Fast scroll sound 1 - * To be by the framework when a fast-scrolling is performed and - * {@link #areFastScrollSoundEffectsEnabled()} is true. + * @hide Navigation repeat sound 1 + * <p> + * To be played by the framework when a focus navigation is repeatedly triggered + * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. * This is currently only used on TV devices. * Note that this sound is only available if a sound file is specified in audio_assets.xml * @see #playSoundEffect(int) */ - public static final int FX_FAST_SCROLL_1 = 12; + public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12; /** - * @hide Fast scroll sound 2 - * To be by the framework when a fast-scrolling is performed and - * {@link #areFastScrollSoundEffectsEnabled()} is true. + * @hide Navigation repeat sound 2 + * <p> + * To be played by the framework when a focus navigation is repeatedly triggered + * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. * This is currently only used on TV devices. * Note that this sound is only available if a sound file is specified in audio_assets.xml * @see #playSoundEffect(int) */ - public static final int FX_FAST_SCROLL_2 = 13; + public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13; /** - * @hide Fast scroll sound 3 - * To be by the framework when a fast-scrolling is performed and - * {@link #areFastScrollSoundEffectsEnabled()} is true. + * @hide Navigation repeat sound 3 + * <p> + * To be played by the framework when a focus navigation is repeatedly triggered + * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. * This is currently only used on TV devices. * Note that this sound is only available if a sound file is specified in audio_assets.xml * @see #playSoundEffect(int) */ - public static final int FX_FAST_SCROLL_3 = 14; + public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14; /** - * @hide Fast scroll sound 4 - * To be by the framework when a fast-scrolling is performed and - * {@link #areFastScrollSoundEffectsEnabled()} is true. + * @hide Navigation repeat sound 4 + * <p> + * To be played by the framework when a focus navigation is repeatedly triggered + * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. * This is currently only used on TV devices. * Note that this sound is only available if a sound file is specified in audio_assets.xml * @see #playSoundEffect(int) */ - public static final int FX_FAST_SCROLL_4 = 15; + public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15; /** * @hide Number of sound effects @@ -3177,27 +3182,27 @@ public class AudioManager { public static final int NUM_SOUND_EFFECTS = 16; /** - * @hide Number of fast scroll sound effects + * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects */ - public static final int NUM_FAST_SCROLL_SOUND_EFFECTS = 4; + public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4; /** * @hide - * @param n a value in [0, {@link #NUM_FAST_SCROLL_SOUND_EFFECTS}[ - * @return The id of a fast scroll sound effect or -1 if out of bounds + * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[ + * @return The id of a navigation repeat sound effect or -1 if out of bounds */ - public static int getNthFastScrollSoundEffectId(int n) { + public static int getNthNavigationRepeatSoundEffect(int n) { switch (n) { case 0: - return FX_FAST_SCROLL_1; + return FX_FOCUS_NAVIGATION_REPEAT_1; case 1: - return FX_FAST_SCROLL_2; + return FX_FOCUS_NAVIGATION_REPEAT_2; case 2: - return FX_FAST_SCROLL_3; + return FX_FOCUS_NAVIGATION_REPEAT_3; case 3: - return FX_FAST_SCROLL_4; + return FX_FOCUS_NAVIGATION_REPEAT_4; default: - Log.w(TAG, "Invalid fast-scroll sound effect id: " + n); + Log.w(TAG, "Invalid navigation repeat sound effect id: " + n); return -1; } } @@ -3205,9 +3210,9 @@ public class AudioManager { /** * @hide */ - public void setFastScrollSoundEffectsEnabled(boolean enabled) { + public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) { try { - getService().setFastScrollSoundEffectsEnabled(enabled); + getService().setNavigationRepeatSoundEffectsEnabled(enabled); } catch (RemoteException e) { } @@ -3215,11 +3220,11 @@ public class AudioManager { /** * @hide - * @return true if the fast scroll sound effects are enabled + * @return true if the navigation repeat sound effects are enabled */ - public boolean areFastScrollSoundEffectsEnabled() { + public boolean areNavigationRepeatSoundEffectsEnabled() { try { - return getService().areFastScrollSoundEffectsEnabled(); + return getService().areNavigationRepeatSoundEffectsEnabled(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 71ee57e3d471..0073b5cc93b9 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -351,9 +351,9 @@ interface IAudioService { oneway void unregisterCommunicationDeviceDispatcher( ICommunicationDeviceDispatcher dispatcher); - boolean areFastScrollSoundEffectsEnabled(); + boolean areNavigationRepeatSoundEffectsEnabled(); - oneway void setFastScrollSoundEffectsEnabled(boolean enabled); + oneway void setNavigationRepeatSoundEffectsEnabled(boolean enabled); boolean isHomeSoundEffectEnabled(); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 607c8f11e01a..cf31e4141a6d 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -2414,37 +2414,44 @@ final public class MediaCodec implements PlaybackComponent { * This indicates that the requested key was not found when trying to * perform a decrypt operation. The operation can be retried after adding * the correct decryption key. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_NO_KEY}. */ - public static final int ERROR_NO_KEY = 1; + public static final int ERROR_NO_KEY = MediaDrm.ErrorCodes.ERROR_NO_KEY; /** * This indicates that the key used for decryption is no longer * valid due to license term expiration. The operation can be retried * after updating the expired keys. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_KEY_EXPIRED}. */ - public static final int ERROR_KEY_EXPIRED = 2; + public static final int ERROR_KEY_EXPIRED = MediaDrm.ErrorCodes.ERROR_KEY_EXPIRED; /** * This indicates that a required crypto resource was not able to be * allocated while attempting the requested operation. The operation * can be retried if the app is able to release resources. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_RESOURCE_BUSY} */ - public static final int ERROR_RESOURCE_BUSY = 3; + public static final int ERROR_RESOURCE_BUSY = MediaDrm.ErrorCodes.ERROR_RESOURCE_BUSY; /** * This indicates that the output protection levels supported by the * device are not sufficient to meet the requirements set by the * content owner in the license policy. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_INSUFFICIENT_OUTPUT_PROTECTION} */ - public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; + public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION; /** * This indicates that decryption was attempted on a session that is * not opened, which could be due to a failure to open the session, * closing the session prematurely, or the session being reclaimed * by the resource manager. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_SESSION_NOT_OPENED} */ - public static final int ERROR_SESSION_NOT_OPENED = 5; + public static final int ERROR_SESSION_NOT_OPENED = + MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED; /** * This indicates that an operation was attempted that could not be @@ -2453,23 +2460,28 @@ final public class MediaCodec implements PlaybackComponent { * device security features that aren't supported by the device, * or due to an internal error in the crypto system that prevents * the specified security policy from being met. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_UNSUPPORTED_OPERATION} */ - public static final int ERROR_UNSUPPORTED_OPERATION = 6; + public static final int ERROR_UNSUPPORTED_OPERATION = + MediaDrm.ErrorCodes.ERROR_UNSUPPORTED_OPERATION; /** * This indicates that the security level of the device is not * sufficient to meet the requirements set by the content owner * in the license policy. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_INSUFFICIENT_SECURITY} */ - public static final int ERROR_INSUFFICIENT_SECURITY = 7; + public static final int ERROR_INSUFFICIENT_SECURITY = + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_SECURITY; /** * This indicates that the video frame being decrypted exceeds * the size of the device's protected output buffers. When * encountering this error the app should try playing content * of a lower resolution. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_FRAME_TOO_LARGE} */ - public static final int ERROR_FRAME_TOO_LARGE = 8; + public static final int ERROR_FRAME_TOO_LARGE = MediaDrm.ErrorCodes.ERROR_FRAME_TOO_LARGE; /** * This error indicates that session state has been @@ -2477,26 +2489,37 @@ final public class MediaCodec implements PlaybackComponent { * of retaining crypto session state across device * suspend/resume. The session must be closed and a new * session opened to resume operation. + * @deprecated Please use {@link MediaDrm.ErrorCodes#ERROR_LOST_STATE} */ - public static final int ERROR_LOST_STATE = 9; + public static final int ERROR_LOST_STATE = MediaDrm.ErrorCodes.ERROR_LOST_STATE; /** @hide */ @IntDef({ - ERROR_NO_KEY, - ERROR_KEY_EXPIRED, - ERROR_RESOURCE_BUSY, - ERROR_INSUFFICIENT_OUTPUT_PROTECTION, - ERROR_SESSION_NOT_OPENED, - ERROR_UNSUPPORTED_OPERATION, - ERROR_INSUFFICIENT_SECURITY, - ERROR_FRAME_TOO_LARGE, - ERROR_LOST_STATE + MediaDrm.ErrorCodes.ERROR_NO_KEY, + MediaDrm.ErrorCodes.ERROR_KEY_EXPIRED, + MediaDrm.ErrorCodes.ERROR_RESOURCE_BUSY, + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION, + MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED, + MediaDrm.ErrorCodes.ERROR_UNSUPPORTED_OPERATION, + MediaDrm.ErrorCodes.ERROR_INSUFFICIENT_SECURITY, + MediaDrm.ErrorCodes.ERROR_FRAME_TOO_LARGE, + MediaDrm.ErrorCodes.ERROR_LOST_STATE, + MediaDrm.ErrorCodes.ERROR_GENERIC_OEM, + MediaDrm.ErrorCodes.ERROR_GENERIC_PLUGIN, + MediaDrm.ErrorCodes.ERROR_LICENSE_PARSE, + MediaDrm.ErrorCodes.ERROR_MEDIA_FRAMEWORK, + MediaDrm.ErrorCodes.ERROR_ZERO_SUBSAMPLES }) @Retention(RetentionPolicy.SOURCE) public @interface CryptoErrorCode {} /** - * Retrieve the error code associated with a CryptoException + * Returns error code associated with this {@link CryptoException}. + * <p> + * Please refer to {@link MediaDrm.ErrorCodes} for the general error + * handling strategy and details about each possible return value. + * + * @return an error code defined in {@link MediaDrm.ErrorCodes}. */ @CryptoErrorCode public int getErrorCode() { diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 49f9d6612341..f7467a636024 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -23,7 +23,11 @@ import android.annotation.Nullable; import android.annotation.StringDef; import android.annotation.TestApi; import android.app.ActivityThread; +import android.app.Application; import android.compat.annotation.UnsupportedAppUsage; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; import android.media.metrics.PlaybackComponent; import android.os.Handler; import android.os.HandlerExecutor; @@ -38,7 +42,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; +import java.time.Instant; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Base64; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; @@ -143,6 +151,7 @@ public final class MediaDrm implements AutoCloseable { private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES; private long mNativeContext; + private final String mAppPackageName; /** * Specify no certificate type @@ -280,16 +289,371 @@ public final class MediaDrm implements AutoCloseable { /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ + mAppPackageName = ActivityThread.currentOpPackageName(); native_setup(new WeakReference<MediaDrm>(this), - getByteArrayFromUUID(uuid), ActivityThread.currentOpPackageName()); + getByteArrayFromUUID(uuid), mAppPackageName); mCloseGuard.open("release"); } /** - * Thrown when an unrecoverable failure occurs during a MediaDrm operation. - * Extends java.lang.IllegalStateException with the addition of an error + * Error codes that may be returned from {@link + * MediaDrmStateException#getErrorCode()} and {@link + * MediaCodec.CryptoException#getErrorCode()} + * <p> + * The description of each error code includes steps that may be taken to + * resolve the error condition. For some errors however, a recovery action + * cannot be predetermined. The description of those codes refers to a + * general strategy for handling the error condition programmatically, which + * is to try the following in listed order until successful: + * <ol> + * <li> retry the operation </li> + * <li> if the operation is related to a session, {@link + * #closeSession(byte[]) close} the session, {@link #openSession() open} a + * new session, and retry the operation </li> + * <li> {@link #close() close} the {@link MediaDrm} instance and any other + * related components such as the {@link MediaCodec codec} and retry + * playback, or </li> + * <li> try using a different configuration of the {@link MediaDrm} plugin, + * such as a different {@link #openSession(int) security level}. </li> + * </ol> + * <p> + * If the problem still persists after all the aforementioned steps, please + * report the failure to the {@link MediaDrm} plugin vendor along with the + * {@link LogMessage log messages} returned by {@link + * MediaDrm#getLogMessages()}, and a bugreport if possible. + */ + public final static class ErrorCodes { + private ErrorCodes() {} + + /** + * ERROR_UNKNOWN is used where no other defined error code is applicable + * to the current failure. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_UNKNOWN = 0; + + /** + * The requested key was not found when trying to perform a decrypt + * operation. + * <p> + * The operation can be retried after adding the correct decryption key. + */ + public static final int ERROR_NO_KEY = 1; + + /** + * The key used for decryption is no longer valid due to license term + * expiration. + * <p> + * The operation can be retried after updating the expired keys. + */ + public static final int ERROR_KEY_EXPIRED = 2; + + /** + * A required crypto resource was not able to be allocated while + * attempting the requested operation. + * <p> + * The operation can be retried if the app is able to release resources. + */ + public static final int ERROR_RESOURCE_BUSY = 3; + + /** + * The output protection levels supported by the device are not + * sufficient to meet the requirements set by the content owner in the + * license policy. + */ + public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; + + /** + * Decryption was attempted on a session that is not opened, which could + * be due to a failure to open the session, closing the session + * prematurely, the session being reclaimed by the resource manager, or + * a non-existent session id. + */ + public static final int ERROR_SESSION_NOT_OPENED = 5; + + /** + * An operation was attempted that could not be supported by the crypto + * system of the device in its current configuration. + * <p> + * This may occur when the license policy requires device security + * features that aren't supported by the device, or due to an internal + * error in the crypto system that prevents the specified security + * policy from being met. + */ + public static final int ERROR_UNSUPPORTED_OPERATION = 6; + + /** + * The security level of the device is not sufficient to meet the + * requirements set by the content owner in the license policy. + */ + public static final int ERROR_INSUFFICIENT_SECURITY = 7; + + /** + * The video frame being decrypted exceeds the size of the device's + * protected output buffers. + * <p> + * When encountering this error the app should try playing content + * of a lower resolution or skipping the problematic frame. + */ + public static final int ERROR_FRAME_TOO_LARGE = 8; + + /** + * The session state has been invalidated. This can occur on devices + * that are not capable of retaining crypto session state across device + * suspend/resume. + * <p> + * The session must be closed and a new session opened to resume + * operation. + */ + public static final int ERROR_LOST_STATE = 9; + + /** + * Certificate is malformed or is of the wrong type. + * <p> + * Ensure the certificate provided by the app or returned from the + * license server is valid. Check with the {@link MediaDrm} plugin + * vendor for the expected certificate format. + */ + public static final int ERROR_CERTIFICATE_MALFORMED = 10; + + /** + * Certificate has not been set. + * <p> + * Ensure the certificate has been provided by the app. Check with the + * {@link MediaDrm} plugin vendor for the expected method to provide + * {@link MediaDrm} a certificate. + */ + public static final int ERROR_CERTIFICATE_MISSING = 11; + + /** + * An error happened within the crypto library used by the drm plugin. + */ + public static final int ERROR_CRYPTO_LIBRARY = 12; + + /** + * Unexpected error reported by the device OEM subsystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_GENERIC_OEM = 13; + + /** + * Unexpected internal failure in {@link MediaDrm}/{@link MediaCrypto}. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_GENERIC_PLUGIN = 14; + + /** + * The init data parameter passed to {@link MediaDrm#getKeyRequest} is + * empty or invalid. + * <p> + * Init data is typically obtained from {@link + * MediaExtractor#getPsshInfo()} or {@link + * MediaExtractor#getDrmInitData()}. Check with the {@link MediaDrm} + * plugin vendor for the expected init data format. + */ + public static final int ERROR_INIT_DATA = 15; + + /** + * Either the key was not loaded from the license before attempting the + * operation, or the key ID parameter provided by the app is incorrect. + * <p> + * Ensure the proper keys are in the license, and check the key ID + * parameter provided by the app is correct. Check with the {@link + * MediaDrm} plugin vendor for the expected license format. + */ + public static final int ERROR_KEY_NOT_LOADED = 16; + + /** + * The license response was empty, fields are missing or otherwise + * unable to be parsed or decrypted. + * <p> + * Check for mistakes such as empty or overwritten buffers. Otherwise, + * check with the {@link MediaDrm} plugin vendor for the expected + * license format. + */ + public static final int ERROR_LICENSE_PARSE = 17; + + /** + * The operation (e.g. to renew or persist a license) is prohibited by + * the license policy. + * <p> + * Check the license policy configuration on the license server. + */ + public static final int ERROR_LICENSE_POLICY = 18; + + /** + * Failed to generate a release request because a field in the offline + * license is empty or malformed. + * <p> + * The license can't be released on the server, but the app may remove + * the offline license explicitly using {@link + * MediaDrm#removeOfflineLicense}. + */ + public static final int ERROR_LICENSE_RELEASE = 19; + + /** + * The license server detected an error in the license request. + * <p> + * Check for errors on the license server. + */ + public static final int ERROR_LICENSE_REQUEST_REJECTED = 20; + + /** + * Failed to restore an offline license because a field in the offline + * license is empty or malformed. + * <p> + * Try requesting the license again if the device is online. + */ + public static final int ERROR_LICENSE_RESTORE = 21; + + /** + * Offline license is in an invalid state for the attempted operation. + * <p> + * Check the sequence of API calls made that can affect offline license + * state. For example, this could happen when the app attempts to + * restore a license after it has been released. + */ + public static final int ERROR_LICENSE_STATE = 22; + + /** + * Failure in the media framework. + * <p> + * Try releasing media resources (e.g. {@link MediaCodec}, {@link + * MediaDrm}), and restarting playback. + */ + public static final int ERROR_MEDIA_FRAMEWORK = 23; + + /** + * Error loading the provisioned certificate. + * <p> + * Re-provisioning may resolve the problem; check with the {@link + * MediaDrm} plugin vendor for re-provisioning instructions. Otherwise, + * using a different security level may resolve the issue. + */ + public static final int ERROR_PROVISIONING_CERTIFICATE = 24; + + /** + * Required steps were not performed before provisioning was attempted. + * <p> + * Ask the {@link MediaDrm} plugin vendor for situations where this + * error may occur. + */ + public static final int ERROR_PROVISIONING_CONFIG = 25; + + /** + * The provisioning response was empty, fields are missing or otherwise + * unable to be parsed. + * <p> + * Check for mistakes such as empty or overwritten buffers. Otherwise, + * check with the {@link MediaDrm} plugin vendor for the expected + * provisioning response format. + */ + public static final int ERROR_PROVISIONING_PARSE = 26; + + /** + * Provisioning failed in a way that is likely to succeed on a + * subsequent attempt. + * <p> + * The app should retry the operation. + */ + public static final int ERROR_PROVISIONING_RETRY = 27; + + /** + * This indicates that apps using MediaDrm sessions are + * temporarily exceeding the capacity of available crypto + * resources. + * <p> + * The app should retry the operation later. + */ + public static final int ERROR_RESOURCE_CONTENTION = 28; + + /** + * Failed to generate a secure stop request because a field in the + * stored license is empty or malformed. + * <p> + * The secure stop can't be released on the server, but the app may + * remove it explicitly using {@link MediaDrm#removeSecureStop}. + */ + public static final int ERROR_SECURE_STOP_RELEASE = 29; + + /** + * The plugin was unable to read data from the filesystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_STORAGE_READ = 30; + + /** + * The plugin was unable to write data to the filesystem. + * <p> + * Please see the general error handling strategy for unexpected errors + * described in {@link ErrorCodes}. + */ + public static final int ERROR_STORAGE_WRITE = 31; + + /** + * {@link MediaCodec#queueSecureInputBuffer} called with 0 subsamples. + * <p> + * Check the {@link MediaCodec.CryptoInfo} object passed to {@link + * MediaCodec#queueSecureInputBuffer}. + */ + public static final int ERROR_ZERO_SUBSAMPLES = 32; + + } + + /** @hide */ + @IntDef({ + ErrorCodes.ERROR_NO_KEY, + ErrorCodes.ERROR_KEY_EXPIRED, + ErrorCodes.ERROR_RESOURCE_BUSY, + ErrorCodes.ERROR_INSUFFICIENT_OUTPUT_PROTECTION, + ErrorCodes.ERROR_SESSION_NOT_OPENED, + ErrorCodes.ERROR_UNSUPPORTED_OPERATION, + ErrorCodes.ERROR_INSUFFICIENT_SECURITY, + ErrorCodes.ERROR_FRAME_TOO_LARGE, + ErrorCodes.ERROR_LOST_STATE, + ErrorCodes.ERROR_CERTIFICATE_MALFORMED, + ErrorCodes.ERROR_CERTIFICATE_MISSING, + ErrorCodes.ERROR_CRYPTO_LIBRARY, + ErrorCodes.ERROR_GENERIC_OEM, + ErrorCodes.ERROR_GENERIC_PLUGIN, + ErrorCodes.ERROR_INIT_DATA, + ErrorCodes.ERROR_KEY_NOT_LOADED, + ErrorCodes.ERROR_LICENSE_PARSE, + ErrorCodes.ERROR_LICENSE_POLICY, + ErrorCodes.ERROR_LICENSE_RELEASE, + ErrorCodes.ERROR_LICENSE_REQUEST_REJECTED, + ErrorCodes.ERROR_LICENSE_RESTORE, + ErrorCodes.ERROR_LICENSE_STATE, + ErrorCodes.ERROR_MEDIA_FRAMEWORK, + ErrorCodes.ERROR_PROVISIONING_CERTIFICATE, + ErrorCodes.ERROR_PROVISIONING_CONFIG, + ErrorCodes.ERROR_PROVISIONING_PARSE, + ErrorCodes.ERROR_PROVISIONING_RETRY, + ErrorCodes.ERROR_SECURE_STOP_RELEASE, + ErrorCodes.ERROR_STORAGE_READ, + ErrorCodes.ERROR_STORAGE_WRITE, + ErrorCodes.ERROR_ZERO_SUBSAMPLES + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MediaDrmErrorCode {} + + /** + * Thrown when a general failure occurs during a MediaDrm operation. + * Extends {@link IllegalStateException} with the addition of an error * code that may be useful in diagnosing the failure. + * <p> + * Please refer to {@link ErrorCodes} for the general error handling + * strategy and details about each possible return value from {@link + * MediaDrmStateException#getErrorCode()}. */ public static final class MediaDrmStateException extends java.lang.IllegalStateException { private final int mErrorCode; @@ -310,15 +674,30 @@ public final class MediaDrm implements AutoCloseable { } /** - * Retrieve the associated error code + * Returns error code associated with this {@link + * MediaDrmStateException}. + * <p> + * Please refer to {@link ErrorCodes} for the general error handling + * strategy and details about each possible return value. * - * @hide + * @return an error code defined in {@link MediaDrm.ErrorCodes}. */ + @MediaDrmErrorCode public int getErrorCode() { return mErrorCode; } /** + * Returns true if the {@link MediaDrmStateException} is a transient + * issue, perhaps due to resource constraints, and that the operation + * (e.g. provisioning) may succeed on a subsequent attempt. + */ + public boolean isTransient() { + return mErrorCode == ErrorCodes.ERROR_PROVISIONING_RETRY + || mErrorCode == ErrorCodes.ERROR_RESOURCE_CONTENTION; + } + + /** * Retrieve a developer-readable diagnostic information string * associated with the exception. Do not show this to end-users, * since this string will not be localized or generally comprehensible @@ -331,7 +710,13 @@ public final class MediaDrm implements AutoCloseable { } /** - * Thrown when an error occurs in any method that has a session context. + * {@link SessionException} is a misnomer because it may occur in methods + * <b>without</b> a session context. + * <p> + * A {@link SessionException} is most likely to be thrown when an operation + * failed in a way that is likely to succeed on a subsequent attempt; call + * {@link #isTransient()} to determine whether the app should retry the + * failing operation. */ public static final class SessionException extends RuntimeException { public SessionException(int errorCode, @Nullable String detailMessage) { @@ -341,6 +726,7 @@ public final class MediaDrm implements AutoCloseable { /** * The SessionException has an unknown error code. + * @deprecated Unused. */ public static final int ERROR_UNKNOWN = 0; @@ -348,6 +734,10 @@ public final class MediaDrm implements AutoCloseable { * This indicates that apps using MediaDrm sessions are * temporarily exceeding the capacity of available crypto * resources. The app should retry the operation later. + * + * @deprecated Please use {@link #isTransient()} instead of comparing + * the return value of {@link #getErrorCode()} against + * {@link SessionException#ERROR_RESOURCE_CONTENTION}. */ public static final int ERROR_RESOURCE_CONTENTION = 1; @@ -360,12 +750,26 @@ public final class MediaDrm implements AutoCloseable { /** * Retrieve the error code associated with the SessionException + * + * @deprecated Please use {@link #isTransient()} instead of comparing + * the return value of {@link #getErrorCode()} against + * {@link SessionException#ERROR_RESOURCE_CONTENTION}. */ @SessionErrorCode public int getErrorCode() { return mErrorCode; } + /** + * Returns true if the {@link SessionException} is a transient + * issue, perhaps due to resource constraints, and that the operation + * (e.g. provisioning, generating requests) may succeed on a subsequent + * attempt. + */ + public boolean isTransient() { + return mErrorCode == ERROR_RESOURCE_CONTENTION; + } + private final int mErrorCode; } @@ -1143,12 +1547,78 @@ public final class MediaDrm implements AutoCloseable { * problem with the certifcate */ @NonNull - public native KeyRequest getKeyRequest( + public KeyRequest getKeyRequest( @NonNull byte[] scope, @Nullable byte[] init, @Nullable String mimeType, @KeyType int keyType, @Nullable HashMap<String, String> optionalParameters) - throws NotProvisionedException; + throws NotProvisionedException { + HashMap<String, String> internalParams; + if (optionalParameters == null) { + internalParams = new HashMap<>(); + } else { + internalParams = new HashMap<>(optionalParameters); + } + byte[] rawBytes = getNewestAvailablePackageCertificateRawBytes(); + byte[] hashBytes = null; + if (rawBytes != null) { + hashBytes = getDigestBytes(rawBytes, "SHA-256"); + } + if (hashBytes != null) { + Base64.Encoder encoderB64 = Base64.getEncoder(); + String hashBytesB64 = encoderB64.encodeToString(hashBytes); + internalParams.put("package_certificate_hash_bytes", hashBytesB64); + } + return getKeyRequestNative(scope, init, mimeType, keyType, internalParams); + } + @Nullable + private byte[] getNewestAvailablePackageCertificateRawBytes() { + Application application = ActivityThread.currentApplication(); + if (application == null) { + Log.w(TAG, "pkg cert: Application is null"); + return null; + } + PackageManager pm = application.getPackageManager(); + if (pm == null) { + Log.w(TAG, "pkg cert: PackageManager is null"); + return null; + } + PackageInfo packageInfo = null; + try { + packageInfo = pm.getPackageInfo(mAppPackageName, + PackageManager.GET_SIGNING_CERTIFICATES); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, mAppPackageName, e); + } + if (packageInfo == null || packageInfo.signingInfo == null) { + Log.w(TAG, "pkg cert: PackageInfo or SigningInfo is null"); + return null; + } + Signature[] signers = packageInfo.signingInfo.getApkContentsSigners(); + if (signers != null && signers.length == 1) { + return signers[0].toByteArray(); + } + Log.w(TAG, "pkg cert: " + signers.length + " signers"); + return null; + } + + @Nullable + private static byte[] getDigestBytes(@NonNull byte[] rawBytes, @NonNull String algorithm) { + try { + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + return messageDigest.digest(rawBytes); + } catch (NoSuchAlgorithmException e) { + Log.w(TAG, algorithm, e); + } + return null; + } + + @NonNull + private native KeyRequest getKeyRequestNative( + @NonNull byte[] scope, @Nullable byte[] init, + @Nullable String mimeType, @KeyType int keyType, + @Nullable HashMap<String, String> optionalParameters) + throws NotProvisionedException; /** * A key response is received from the license server by the app, then it is @@ -2493,4 +2963,80 @@ public final class MediaDrm implements AutoCloseable { return mPlaybackId; } } + + /** + * Returns recent {@link LogMessage LogMessages} associated with this {@link MediaDrm} + * instance. + */ + @NonNull + public native List<LogMessage> getLogMessages(); + + /** + * A {@link LogMessage} records an event in the {@link MediaDrm} framework + * or vendor plugin. + */ + public static class LogMessage { + + /** + * Timing of the recorded event measured in milliseconds since the Epoch, + * 1970-01-01 00:00:00 +0000 (UTC). + */ + public final long timestampMillis; + + /** + * Priority of the recorded event. + * <p> + * Possible priority constants are defined in {@link Log}, e.g.: + * <ul> + * <li>{@link Log#ASSERT}</li> + * <li>{@link Log#ERROR}</li> + * <li>{@link Log#WARN}</li> + * <li>{@link Log#INFO}</li> + * <li>{@link Log#DEBUG}</li> + * <li>{@link Log#VERBOSE}</li> + * </ul> + */ + @Log.Level + public final int priority; + + /** + * Description of the recorded event. + */ + @NonNull + public final String message; + + private LogMessage(long timestampMillis, int priority, String message) { + this.timestampMillis = timestampMillis; + if (priority < Log.VERBOSE || priority > Log.ASSERT) { + throw new IllegalArgumentException("invalid log priority " + priority); + } + this.priority = priority; + this.message = message; + } + + private char logPriorityChar() { + switch (priority) { + case Log.VERBOSE: + return 'V'; + case Log.DEBUG: + return 'D'; + case Log.INFO: + return 'I'; + case Log.WARN: + return 'W'; + case Log.ERROR: + return 'E'; + case Log.ASSERT: + return 'F'; + default: + } + return 'U'; + } + + @Override + public String toString() { + return String.format("LogMessage{%s %c %s}", + Instant.ofEpochMilli(timestampMillis), logPriorityChar(), message); + } + } } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 2c45ed3cb861..c51c9dd06c24 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -921,7 +921,7 @@ public class MediaPlayer extends PlayerBase final AudioAttributes aa = audioAttributes != null ? audioAttributes : new AudioAttributes.Builder().build(); mp.setAudioAttributes(aa); - mp.setAudioSessionId(audioSessionId); + mp.native_setAudioSessionId(audioSessionId); mp.setDataSource(context, uri); if (holder != null) { mp.setDisplay(holder); @@ -987,7 +987,7 @@ public class MediaPlayer extends PlayerBase final AudioAttributes aa = audioAttributes != null ? audioAttributes : new AudioAttributes.Builder().build(); mp.setAudioAttributes(aa); - mp.setAudioSessionId(audioSessionId); + mp.native_setAudioSessionId(audioSessionId); mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); afd.close(); diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 6cf99e288f1b..dc43ad342725 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -384,7 +384,12 @@ public class MediaRouter { } public Display[] getAllPresentationDisplays() { - return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + try { + return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + } catch (RuntimeException ex) { + Log.e(TAG, "Unable to get displays.", ex); + return null; + } } private void updatePresentationDisplays(int changedDisplayId) { diff --git a/media/java/android/media/metrics/NetworkEvent.java b/media/java/android/media/metrics/NetworkEvent.java index a330bc0b66df..029edeb93374 100644 --- a/media/java/android/media/metrics/NetworkEvent.java +++ b/media/java/android/media/metrics/NetworkEvent.java @@ -17,6 +17,7 @@ package android.media.metrics; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -27,22 +28,30 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * Playback network event. - * @hide + * Media network event. */ -public final class NetworkEvent implements Parcelable { +public final class NetworkEvent extends Event implements Parcelable { + /** Network type is not specified. Default type. */ public static final int NETWORK_TYPE_NONE = 0; + /** Other network type */ public static final int NETWORK_TYPE_OTHER = 1; + /** Wi-Fi network */ public static final int NETWORK_TYPE_WIFI = 2; + /** Ethernet network */ public static final int NETWORK_TYPE_ETHERNET = 3; + /** 2G network */ public static final int NETWORK_TYPE_2G = 4; + /** 3G network */ public static final int NETWORK_TYPE_3G = 5; + /** 4G network */ public static final int NETWORK_TYPE_4G = 6; + /** 5G NSA network */ public static final int NETWORK_TYPE_5G_NSA = 7; + /** 5G SA network */ public static final int NETWORK_TYPE_5G_SA = 8; - private final int mType; - private final long mTimeSincePlaybackCreatedMillis; + private final int mNetworkType; + private final long mTimeSinceCreatedMillis; /** @hide */ @IntDef(prefix = "NETWORK_TYPE_", value = { @@ -61,6 +70,7 @@ public final class NetworkEvent implements Parcelable { /** * Network type to string. + * @hide */ public static String networkTypeToString(@NetworkType int value) { switch (value) { @@ -92,25 +102,34 @@ public final class NetworkEvent implements Parcelable { * * @hide */ - public NetworkEvent(@NetworkType int type, long timeSincePlaybackCreatedMillis) { - this.mType = type; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + public NetworkEvent(@NetworkType int type, long timeSinceCreatedMillis) { + this.mNetworkType = type; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; } + /** + * Gets network type. + */ @NetworkType - public int getType() { - return mType; + public int getNetworkType() { + return mNetworkType; } - public long getTimeSincePlaybackCreatedMillis() { - return mTimeSincePlaybackCreatedMillis; + /** + * Gets timestamp since the creation in milliseconds. + * @return the timestamp since the creation in milliseconds, or -1 if unknown. + */ + @Override + @IntRange(from = -1) + public long getTimeSinceCreatedMillis() { + return mTimeSinceCreatedMillis; } @Override public String toString() { return "NetworkEvent { " - + "type = " + mType + ", " - + "timeSincePlaybackCreatedMillis = " + mTimeSincePlaybackCreatedMillis + + "networkType = " + mNetworkType + ", " + + "timeSinceCreatedMillis = " + mTimeSinceCreatedMillis + " }"; } @@ -119,19 +138,19 @@ public final class NetworkEvent implements Parcelable { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NetworkEvent that = (NetworkEvent) o; - return mType == that.mType - && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis; + return mNetworkType == that.mNetworkType + && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis; } @Override public int hashCode() { - return Objects.hash(mType, mTimeSincePlaybackCreatedMillis); + return Objects.hash(mNetworkType, mTimeSinceCreatedMillis); } @Override public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { - dest.writeInt(mType); - dest.writeLong(mTimeSincePlaybackCreatedMillis); + dest.writeInt(mNetworkType); + dest.writeLong(mTimeSinceCreatedMillis); } @Override @@ -142,12 +161,15 @@ public final class NetworkEvent implements Parcelable { /** @hide */ /* package-private */ NetworkEvent(@NonNull android.os.Parcel in) { int type = in.readInt(); - long timeSincePlaybackCreatedMillis = in.readLong(); + long timeSinceCreatedMillis = in.readLong(); - this.mType = type; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + this.mNetworkType = type; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; } + /** + * Used to read a NetworkEvent from a Parcel. + */ public static final @NonNull Parcelable.Creator<NetworkEvent> CREATOR = new Parcelable.Creator<NetworkEvent>() { @Override @@ -165,13 +187,11 @@ public final class NetworkEvent implements Parcelable { * A builder for {@link NetworkEvent} */ public static final class Builder { - private int mType; - private long mTimeSincePlaybackCreatedMillis; + private int mNetworkType = NETWORK_TYPE_NONE; + private long mTimeSinceCreatedMillis = -1; /** * Creates a new Builder. - * - * @hide */ public Builder() { } @@ -179,24 +199,24 @@ public final class NetworkEvent implements Parcelable { /** * Sets network type. */ - public @NonNull Builder setType(@NetworkType int value) { - mType = value; + public @NonNull Builder setNetworkType(@NetworkType int value) { + mNetworkType = value; return this; } /** * Sets timestamp since the creation in milliseconds. + * @param value the timestamp since the creation in milliseconds. + * -1 indicates the value is unknown. */ - public @NonNull Builder setTimeSincePlaybackCreatedMillis(long value) { - mTimeSincePlaybackCreatedMillis = value; + public @NonNull Builder setTimeSinceCreatedMillis(@IntRange(from = -1) long value) { + mTimeSinceCreatedMillis = value; return this; } /** Builds the instance. */ public @NonNull NetworkEvent build() { - NetworkEvent o = new NetworkEvent( - mType, - mTimeSincePlaybackCreatedMillis); + NetworkEvent o = new NetworkEvent(mNetworkType, mTimeSinceCreatedMillis); return o; } } diff --git a/media/java/android/media/metrics/PlaybackComponent.java b/media/java/android/media/metrics/PlaybackComponent.java index 94e55b4843c1..1cadf3be38ee 100644 --- a/media/java/android/media/metrics/PlaybackComponent.java +++ b/media/java/android/media/metrics/PlaybackComponent.java @@ -17,13 +17,10 @@ package android.media.metrics; import android.annotation.NonNull; -import android.annotation.TestApi; /** * Interface for playback related components used by playback metrics. - * @hide */ -@TestApi public interface PlaybackComponent { /** diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java index db7000536299..5a0820d16cb9 100644 --- a/media/java/android/media/metrics/PlaybackErrorEvent.java +++ b/media/java/android/media/metrics/PlaybackErrorEvent.java @@ -17,8 +17,10 @@ package android.media.metrics; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.os.Parcel; import android.os.Parcelable; @@ -27,17 +29,19 @@ import java.util.Objects; /** * Playback error event. - * @hide */ -public final class PlaybackErrorEvent implements Parcelable { +public final class PlaybackErrorEvent extends Event implements Parcelable { + /** Unknown error code. */ public static final int ERROR_CODE_UNKNOWN = 0; + /** Error code for other errors */ public static final int ERROR_CODE_OTHER = 1; + /** Error code for runtime errors */ public static final int ERROR_CODE_RUNTIME = 2; private final @Nullable String mExceptionStack; private final int mErrorCode; private final int mSubErrorCode; - private final long mTimeSincePlaybackCreatedMillis; + private final long mTimeSinceCreatedMillis; /** @hide */ @@ -59,11 +63,11 @@ public final class PlaybackErrorEvent implements Parcelable { @Nullable String exceptionStack, int errorCode, int subErrorCode, - long timeSincePlaybackCreatedMillis) { + long timeSinceCreatedMillis) { this.mExceptionStack = exceptionStack; this.mErrorCode = errorCode; this.mSubErrorCode = subErrorCode; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; } /** @hide */ @@ -72,17 +76,32 @@ public final class PlaybackErrorEvent implements Parcelable { return mExceptionStack; } + + /** + * Gets error code. + */ @ErrorCode public int getErrorCode() { return mErrorCode; } + + /** + * Gets sub error code. + */ + @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) public int getSubErrorCode() { return mSubErrorCode; } - public long getTimeSincePlaybackCreatedMillis() { - return mTimeSincePlaybackCreatedMillis; + /** + * Gets the timestamp since creation in milliseconds. + * @return the timestamp since the playback is created, or -1 if unknown. + */ + @Override + @IntRange(from = -1) + public long getTimeSinceCreatedMillis() { + return mTimeSinceCreatedMillis; } @Override @@ -91,7 +110,7 @@ public final class PlaybackErrorEvent implements Parcelable { + "exceptionStack = " + mExceptionStack + ", " + "errorCode = " + mErrorCode + ", " + "subErrorCode = " + mSubErrorCode + ", " - + "timeSincePlaybackCreatedMillis = " + mTimeSincePlaybackCreatedMillis + + "timeSinceCreatedMillis = " + mTimeSinceCreatedMillis + " }"; } @@ -103,13 +122,13 @@ public final class PlaybackErrorEvent implements Parcelable { return Objects.equals(mExceptionStack, that.mExceptionStack) && mErrorCode == that.mErrorCode && mSubErrorCode == that.mSubErrorCode - && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis; + && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis; } @Override public int hashCode() { return Objects.hash(mExceptionStack, mErrorCode, mSubErrorCode, - mTimeSincePlaybackCreatedMillis); + mTimeSinceCreatedMillis); } @Override @@ -120,7 +139,7 @@ public final class PlaybackErrorEvent implements Parcelable { if (mExceptionStack != null) dest.writeString(mExceptionStack); dest.writeInt(mErrorCode); dest.writeInt(mSubErrorCode); - dest.writeLong(mTimeSincePlaybackCreatedMillis); + dest.writeLong(mTimeSinceCreatedMillis); } @Override @@ -134,14 +153,15 @@ public final class PlaybackErrorEvent implements Parcelable { String exceptionStack = (flg & 0x1) == 0 ? null : in.readString(); int errorCode = in.readInt(); int subErrorCode = in.readInt(); - long timeSincePlaybackCreatedMillis = in.readLong(); + long timeSinceCreatedMillis = in.readLong(); this.mExceptionStack = exceptionStack; this.mErrorCode = errorCode; this.mSubErrorCode = subErrorCode; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; } + public static final @NonNull Parcelable.Creator<PlaybackErrorEvent> CREATOR = new Parcelable.Creator<PlaybackErrorEvent>() { @Override @@ -162,27 +182,18 @@ public final class PlaybackErrorEvent implements Parcelable { private @Nullable Exception mException; private int mErrorCode; private int mSubErrorCode; - private long mTimeSincePlaybackCreatedMillis; + private long mTimeSinceCreatedMillis = -1; /** * Creates a new Builder. - * - * @hide */ - public Builder( - @Nullable Exception exception, - int errorCode, - int subErrorCode, - long timeSincePlaybackCreatedMillis) { - mException = exception; - mErrorCode = errorCode; - mSubErrorCode = subErrorCode; - mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + public Builder() { } /** * Sets the {@link Exception} object. */ + @SuppressLint("MissingGetterMatchingBuilder") // Exception is not parcelable. public @NonNull Builder setException(@NonNull Exception value) { mException = value; return this; @@ -199,16 +210,19 @@ public final class PlaybackErrorEvent implements Parcelable { /** * Sets sub error code. */ - public @NonNull Builder setSubErrorCode(int value) { + public @NonNull Builder setSubErrorCode( + @IntRange(from = Integer.MIN_VALUE, to = Integer.MAX_VALUE) int value) { mSubErrorCode = value; return this; } /** - * Set the timestamp in milliseconds. + * Set the timestamp since creation in milliseconds. + * @param value the timestamp since the creation in milliseconds. + * -1 indicates the value is unknown. */ - public @NonNull Builder setTimeSincePlaybackCreatedMillis(long value) { - mTimeSincePlaybackCreatedMillis = value; + public @NonNull Builder setTimeSinceCreatedMillis(@IntRange(from = -1) long value) { + mTimeSinceCreatedMillis = value; return this; } @@ -227,7 +241,7 @@ public final class PlaybackErrorEvent implements Parcelable { stack, mErrorCode, mSubErrorCode, - mTimeSincePlaybackCreatedMillis); + mTimeSinceCreatedMillis); return o; } } diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java index 070b4e4aa14b..4aa61662ba52 100644 --- a/media/java/android/media/metrics/PlaybackMetrics.java +++ b/media/java/android/media/metrics/PlaybackMetrics.java @@ -17,6 +17,7 @@ package android.media.metrics; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -33,35 +34,57 @@ import java.util.Objects; /** * This class is used to store playback data. - * @hide */ public final class PlaybackMetrics implements Parcelable { - // TODO(b/177209128): JavaDoc for the constants. + /** Unknown stream source. */ public static final int STREAM_SOURCE_UNKNOWN = 0; + /** Stream from network. */ public static final int STREAM_SOURCE_NETWORK = 1; + /** Stream from device. */ public static final int STREAM_SOURCE_DEVICE = 2; + /** Stream from more than one sources. */ public static final int STREAM_SOURCE_MIXED = 3; + /** Unknown stream type. */ public static final int STREAM_TYPE_UNKNOWN = 0; + /** Other stream type. */ public static final int STREAM_TYPE_OTHER = 1; + /** Progressive stream type. */ public static final int STREAM_TYPE_PROGRESSIVE = 2; + /** DASH (Dynamic Adaptive Streaming over HTTP) stream type. */ public static final int STREAM_TYPE_DASH = 3; + /** HLS (HTTP Live Streaming) stream type. */ public static final int STREAM_TYPE_HLS = 4; + /** SS (HTTP Smooth Streaming) stream type. */ public static final int STREAM_TYPE_SS = 5; + /** VOD (Video on Demand) playback type. */ public static final int PLAYBACK_TYPE_VOD = 0; + /** Live playback type. */ public static final int PLAYBACK_TYPE_LIVE = 1; + /** Other playback type. */ public static final int PLAYBACK_TYPE_OTHER = 2; + /** DRM is not used. */ public static final int DRM_TYPE_NONE = 0; + /** Other DRM type. */ public static final int DRM_TYPE_OTHER = 1; + /** Play ready DRM type. */ public static final int DRM_TYPE_PLAY_READY = 2; + /** Widevine L1 DRM type. */ public static final int DRM_TYPE_WIDEVINE_L1 = 3; + /** Widevine L3 DRM type. */ public static final int DRM_TYPE_WIDEVINE_L3 = 4; - // TODO: add DRM_TYPE_CLEARKEY + /** Widevine L3 fallback DRM type. */ + public static final int DRM_TYPE_WV_L3_FALLBACK = 5; + /** Clear key DRM type. */ + public static final int DRM_TYPE_CLEARKEY = 6; + /** Main contents. */ public static final int CONTENT_TYPE_MAIN = 0; + /** Advertisement contents. */ public static final int CONTENT_TYPE_AD = 1; + /** Other contents. */ public static final int CONTENT_TYPE_OTHER = 2; @@ -102,7 +125,9 @@ public final class PlaybackMetrics implements Parcelable { DRM_TYPE_OTHER, DRM_TYPE_PLAY_READY, DRM_TYPE_WIDEVINE_L1, - DRM_TYPE_WIDEVINE_L3 + DRM_TYPE_WIDEVINE_L3, + DRM_TYPE_WV_L3_FALLBACK, + DRM_TYPE_CLEARKEY }) @Retention(RetentionPolicy.SOURCE) public @interface DrmType {} @@ -173,6 +198,11 @@ public final class PlaybackMetrics implements Parcelable { this.mNetworkTransferDurationMillis = networkTransferDurationMillis; } + /** + * Gets the media duration in milliseconds. + * @return the media duration in milliseconds, or -1 if unknown. + */ + @IntRange(from = -1) public long getMediaDurationMillis() { return mMediaDurationMillis; } @@ -241,28 +271,36 @@ public final class PlaybackMetrics implements Parcelable { /** * Gets video frames played. + * @return the video frames played, or -1 if unknown. */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getVideoFramesPlayed() { return mVideoFramesPlayed; } /** * Gets video frames dropped. + * @return the video frames dropped, or -1 if unknown. */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getVideoFramesDropped() { return mVideoFramesDropped; } /** * Gets audio underrun count. + * @return the audio underrun count, or -1 if unknown. */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getAudioUnderrunCount() { return mAudioUnderrunCount; } /** * Gets number of network bytes read. + * @return the number of network bytes read, or -1 if unknown. */ + @IntRange(from = -1) public long getNetworkBytesRead() { return mNetworkBytesRead; } @@ -270,6 +308,7 @@ public final class PlaybackMetrics implements Parcelable { /** * Gets number of local bytes read. */ + @IntRange(from = -1) public long getLocalBytesRead() { return mLocalBytesRead; } @@ -277,6 +316,7 @@ public final class PlaybackMetrics implements Parcelable { /** * Gets network transfer duration in milliseconds. */ + @IntRange(from = -1) public long getNetworkTransferDurationMillis() { return mNetworkTransferDurationMillis; } @@ -415,34 +455,33 @@ public final class PlaybackMetrics implements Parcelable { */ public static final class Builder { - private long mMediaDurationMillis; - private int mStreamSource; - private int mStreamType; - private int mPlaybackType; - private int mDrmType; - private int mContentType; + private long mMediaDurationMillis = -1; + private int mStreamSource = STREAM_SOURCE_UNKNOWN; + private int mStreamType = STREAM_TYPE_UNKNOWN; + private int mPlaybackType = PLAYBACK_TYPE_OTHER; + private int mDrmType = DRM_TYPE_NONE; + private int mContentType = CONTENT_TYPE_OTHER; private @Nullable String mPlayerName; private @Nullable String mPlayerVersion; private @NonNull List<Long> mExperimentIds = new ArrayList<>(); - private int mVideoFramesPlayed; - private int mVideoFramesDropped; - private int mAudioUnderrunCount; - private long mNetworkBytesRead; - private long mLocalBytesRead; - private long mNetworkTransferDurationMillis; + private int mVideoFramesPlayed = -1; + private int mVideoFramesDropped = -1; + private int mAudioUnderrunCount = -1; + private long mNetworkBytesRead = -1; + private long mLocalBytesRead = -1; + private long mNetworkTransferDurationMillis = -1; /** * Creates a new Builder. - * - * @hide */ public Builder() { } /** * Sets the media duration in milliseconds. + * @param value the media duration in milliseconds. -1 indicates the value is unknown. */ - public @NonNull Builder setMediaDurationMillis(long value) { + public @NonNull Builder setMediaDurationMillis(@IntRange(from = -1) long value) { mMediaDurationMillis = value; return this; } @@ -474,7 +513,7 @@ public final class PlaybackMetrics implements Parcelable { /** * Sets the DRM type. */ - public @NonNull Builder setDrmType(@StreamType int value) { + public @NonNull Builder setDrmType(@DrmType int value) { mDrmType = value; return this; } @@ -513,48 +552,58 @@ public final class PlaybackMetrics implements Parcelable { /** * Sets the video frames played. + * @param value the video frames played. -1 indicates the value is unknown. */ - public @NonNull Builder setVideoFramesPlayed(int value) { + public @NonNull Builder setVideoFramesPlayed( + @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { mVideoFramesPlayed = value; return this; } /** * Sets the video frames dropped. + * @param value the video frames dropped. -1 indicates the value is unknown. */ - public @NonNull Builder setVideoFramesDropped(int value) { + public @NonNull Builder setVideoFramesDropped( + @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { mVideoFramesDropped = value; return this; } /** * Sets the audio underrun count. + * @param value the audio underrun count. -1 indicates the value is unknown. */ - public @NonNull Builder setAudioUnderrunCount(int value) { + public @NonNull Builder setAudioUnderrunCount( + @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { mAudioUnderrunCount = value; return this; } /** * Sets the number of network bytes read. + * @param value the number of network bytes read. -1 indicates the value is unknown. */ - public @NonNull Builder setNetworkBytesRead(long value) { + public @NonNull Builder setNetworkBytesRead(@IntRange(from = -1) long value) { mNetworkBytesRead = value; return this; } /** * Sets the number of local bytes read. + * @param value the number of local bytes read. -1 indicates the value is unknown. */ - public @NonNull Builder setLocalBytesRead(long value) { + public @NonNull Builder setLocalBytesRead(@IntRange(from = -1) long value) { mLocalBytesRead = value; return this; } /** * Sets the network transfer duration in milliseconds. + * @param value the network transfer duration in milliseconds. + * -1 indicates the value is unknown. */ - public @NonNull Builder setNetworkTransferDurationMillis(long value) { + public @NonNull Builder setNetworkTransferDurationMillis(@IntRange(from = -1) long value) { mNetworkTransferDurationMillis = value; return this; } diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java index 7f3450bcd12f..4ee8a45fe196 100644 --- a/media/java/android/media/metrics/PlaybackSession.java +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -45,7 +45,6 @@ public final class PlaybackSession implements AutoCloseable { /** * Reports playback metrics. - * @hide */ public void reportPlaybackMetrics(@NonNull PlaybackMetrics metrics) { mManager.reportPlaybackMetrics(mId, metrics); @@ -53,17 +52,15 @@ public final class PlaybackSession implements AutoCloseable { /** * Reports error event. - * @hide */ - public void reportPlaybackErrorEvent(PlaybackErrorEvent event) { + public void reportPlaybackErrorEvent(@NonNull PlaybackErrorEvent event) { mManager.reportPlaybackErrorEvent(mId, event); } /** * Reports network event. - * @hide */ - public void reportNetworkEvent(NetworkEvent event) { + public void reportNetworkEvent(@NonNull NetworkEvent event) { mManager.reportNetworkEvent(mId, event); } @@ -76,9 +73,8 @@ public final class PlaybackSession implements AutoCloseable { /** * Reports track change event. - * @hide */ - public void reportTrackChangeEvent(TrackChangeEvent event) { + public void reportTrackChangeEvent(@NonNull TrackChangeEvent event) { mManager.reportTrackChangeEvent(mId, event); } diff --git a/media/java/android/media/metrics/TrackChangeEvent.java b/media/java/android/media/metrics/TrackChangeEvent.java index fff0e36c062a..ef25357457c5 100644 --- a/media/java/android/media/metrics/TrackChangeEvent.java +++ b/media/java/android/media/metrics/TrackChangeEvent.java @@ -17,6 +17,7 @@ package android.media.metrics; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; @@ -28,20 +29,29 @@ import java.util.Objects; /** * Playback track change event. - * @hide */ -public final class TrackChangeEvent implements Parcelable { +public final class TrackChangeEvent extends Event implements Parcelable { + /** The track is off. */ public static final int TRACK_STATE_OFF = 0; + /** The track is on. */ public static final int TRACK_STATE_ON = 1; + /** Unknown track change reason. */ public static final int TRACK_CHANGE_REASON_UNKNOWN = 0; + /** Other track change reason. */ public static final int TRACK_CHANGE_REASON_OTHER = 1; + /** Track change reason for initial state. */ public static final int TRACK_CHANGE_REASON_INITIAL = 2; + /** Track change reason for manual changes. */ public static final int TRACK_CHANGE_REASON_MANUAL = 3; + /** Track change reason for adaptive changes. */ public static final int TRACK_CHANGE_REASON_ADAPTIVE = 4; + /** Audio track. */ public static final int TRACK_TYPE_AUDIO = 0; + /** Video track. */ public static final int TRACK_TYPE_VIDEO = 1; + /** Text track. */ public static final int TRACK_TYPE_TEXT = 2; private final int mState; @@ -50,7 +60,7 @@ public final class TrackChangeEvent implements Parcelable { private final @Nullable String mSampleMimeType; private final @Nullable String mCodecName; private final int mBitrate; - private final long mTimeSincePlaybackCreatedMillis; + private final long mTimeSinceCreatedMillis; private final int mType; private final @Nullable String mLanguage; private final @Nullable String mLanguageRegion; @@ -96,7 +106,7 @@ public final class TrackChangeEvent implements Parcelable { @Nullable String sampleMimeType, @Nullable String codecName, int bitrate, - long timeSincePlaybackCreatedMillis, + long timeSinceCreatedMillis, int type, @Nullable String language, @Nullable String languageRegion, @@ -110,7 +120,7 @@ public final class TrackChangeEvent implements Parcelable { this.mSampleMimeType = sampleMimeType; this.mCodecName = codecName; this.mBitrate = bitrate; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mType = type; this.mLanguage = language; this.mLanguageRegion = languageRegion; @@ -120,34 +130,60 @@ public final class TrackChangeEvent implements Parcelable { this.mHeight = height; } + /** + * Gets track state. + */ @TrackState public int getTrackState() { return mState; } + /** + * Gets track change reason. + */ @TrackChangeReason public int getTrackChangeReason() { return mReason; } + /** + * Gets container MIME type. + */ public @Nullable String getContainerMimeType() { return mContainerMimeType; } + /** + * Gets the MIME type of the video/audio/text samples. + */ public @Nullable String getSampleMimeType() { return mSampleMimeType; } + /** + * Gets codec name. + */ public @Nullable String getCodecName() { return mCodecName; } + /** + * Gets bitrate. + * @return the bitrate, or -1 if unknown. + */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getBitrate() { return mBitrate; } - public long getTimeSincePlaybackCreatedMillis() { - return mTimeSincePlaybackCreatedMillis; + /** + * Gets timestamp since the creation in milliseconds. + * @return the timestamp since the creation in milliseconds, or -1 if unknown. + */ + @Override + @IntRange(from = -1) + public long getTimeSinceCreatedMillis() { + return mTimeSinceCreatedMillis; } @TrackType @@ -155,26 +191,55 @@ public final class TrackChangeEvent implements Parcelable { return mType; } + /** + * Gets language code. + * @return a two-letter ISO 639-1 language code. + */ public @Nullable String getLanguage() { return mLanguage; } + + /** + * Gets language region code. + * @return an IETF BCP 47 optional language region subtag based on a two-letter country code. + */ public @Nullable String getLanguageRegion() { return mLanguageRegion; } + /** + * Gets channel count. + * @return the channel count, or -1 if unknown. + */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getChannelCount() { return mChannelCount; } + /** + * Gets sample rate. + * @return the sample rate, or -1 if unknown. + */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getSampleRate() { return mSampleRate; } + /** + * Gets video width. + * @return the video width, or -1 if unknown. + */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getWidth() { return mWidth; } + /** + * Gets video height. + * @return the video height, or -1 if unknown. + */ + @IntRange(from = -1, to = Integer.MAX_VALUE) public int getHeight() { return mHeight; } @@ -194,7 +259,7 @@ public final class TrackChangeEvent implements Parcelable { if (mSampleMimeType != null) dest.writeString(mSampleMimeType); if (mCodecName != null) dest.writeString(mCodecName); dest.writeInt(mBitrate); - dest.writeLong(mTimeSincePlaybackCreatedMillis); + dest.writeLong(mTimeSinceCreatedMillis); dest.writeInt(mType); if (mLanguage != null) dest.writeString(mLanguage); if (mLanguageRegion != null) dest.writeString(mLanguageRegion); @@ -218,7 +283,7 @@ public final class TrackChangeEvent implements Parcelable { String sampleMimeType = (flg & 0x8) == 0 ? null : in.readString(); String codecName = (flg & 0x10) == 0 ? null : in.readString(); int bitrate = in.readInt(); - long timeSincePlaybackCreatedMillis = in.readLong(); + long timeSinceCreatedMillis = in.readLong(); int type = in.readInt(); String language = (flg & 0x100) == 0 ? null : in.readString(); String languageRegion = (flg & 0x200) == 0 ? null : in.readString(); @@ -233,7 +298,7 @@ public final class TrackChangeEvent implements Parcelable { this.mSampleMimeType = sampleMimeType; this.mCodecName = codecName; this.mBitrate = bitrate; - this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mType = type; this.mLanguage = language; this.mLanguageRegion = languageRegion; @@ -256,38 +321,24 @@ public final class TrackChangeEvent implements Parcelable { } }; - - - // Code below generated by codegen v1.0.22. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/media/java/android/media/metrics/TrackChangeEvent.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - @Override public String toString() { - return "TrackChangeEvent { " + - "state = " + mState + ", " + - "reason = " + mReason + ", " + - "containerMimeType = " + mContainerMimeType + ", " + - "sampleMimeType = " + mSampleMimeType + ", " + - "codecName = " + mCodecName + ", " + - "bitrate = " + mBitrate + ", " + - "timeSincePlaybackCreatedMillis = " + mTimeSincePlaybackCreatedMillis + ", " + - "type = " + mType + ", " + - "language = " + mLanguage + ", " + - "languageRegion = " + mLanguageRegion + ", " + - "channelCount = " + mChannelCount + ", " + - "sampleRate = " + mSampleRate + ", " + - "width = " + mWidth + ", " + - "height = " + mHeight + - " }"; + return "TrackChangeEvent { " + + "state = " + mState + ", " + + "reason = " + mReason + ", " + + "containerMimeType = " + mContainerMimeType + ", " + + "sampleMimeType = " + mSampleMimeType + ", " + + "codecName = " + mCodecName + ", " + + "bitrate = " + mBitrate + ", " + + "timeSinceCreatedMillis = " + mTimeSinceCreatedMillis + ", " + + "type = " + mType + ", " + + "language = " + mLanguage + ", " + + "languageRegion = " + mLanguageRegion + ", " + + "channelCount = " + mChannelCount + ", " + + "sampleRate = " + mSampleRate + ", " + + "width = " + mWidth + ", " + + "height = " + mHeight + + " }"; } @Override @@ -301,7 +352,7 @@ public final class TrackChangeEvent implements Parcelable { && Objects.equals(mSampleMimeType, that.mSampleMimeType) && Objects.equals(mCodecName, that.mCodecName) && mBitrate == that.mBitrate - && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis + && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis && mType == that.mType && Objects.equals(mLanguage, that.mLanguage) && Objects.equals(mLanguageRegion, that.mLanguageRegion) @@ -314,7 +365,7 @@ public final class TrackChangeEvent implements Parcelable { @Override public int hashCode() { return Objects.hash(mState, mReason, mContainerMimeType, mSampleMimeType, mCodecName, - mBitrate, mTimeSincePlaybackCreatedMillis, mType, mLanguage, mLanguageRegion, + mBitrate, mTimeSinceCreatedMillis, mType, mLanguage, mLanguageRegion, mChannelCount, mSampleRate, mWidth, mHeight); } @@ -323,32 +374,33 @@ public final class TrackChangeEvent implements Parcelable { */ public static final class Builder { // TODO: check track type for the setters. - private int mState; - private int mReason; + private int mState = TRACK_STATE_OFF; + private int mReason = TRACK_CHANGE_REASON_UNKNOWN; private @Nullable String mContainerMimeType; private @Nullable String mSampleMimeType; private @Nullable String mCodecName; - private int mBitrate; - private long mTimeSincePlaybackCreatedMillis; - private int mType; + private int mBitrate = -1; + private long mTimeSinceCreatedMillis = -1; + private final int mType; private @Nullable String mLanguage; private @Nullable String mLanguageRegion; - private int mChannelCount; - private int mSampleRate; - private int mWidth; - private int mHeight; + private int mChannelCount = -1; + private int mSampleRate = -1; + private int mWidth = -1; + private int mHeight = -1; private long mBuilderFieldsSet = 0L; /** * Creates a new Builder. - * - * @hide */ public Builder(int type) { mType = type; } + /** + * Sets track state. + */ public @NonNull Builder setTrackState(@TrackState int value) { checkNotUsed(); mBuilderFieldsSet |= 0x1; @@ -356,6 +408,9 @@ public final class TrackChangeEvent implements Parcelable { return this; } + /** + * Sets track change reason. + */ public @NonNull Builder setTrackChangeReason(@TrackChangeReason int value) { checkNotUsed(); mBuilderFieldsSet |= 0x2; @@ -363,6 +418,9 @@ public final class TrackChangeEvent implements Parcelable { return this; } + /** + * Sets container MIME type. + */ public @NonNull Builder setContainerMimeType(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x4; @@ -370,6 +428,9 @@ public final class TrackChangeEvent implements Parcelable { return this; } + /** + * Sets the MIME type of the video/audio/text samples. + */ public @NonNull Builder setSampleMimeType(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x8; @@ -377,6 +438,9 @@ public final class TrackChangeEvent implements Parcelable { return this; } + /** + * Sets codec name. + */ public @NonNull Builder setCodecName(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x10; @@ -384,27 +448,33 @@ public final class TrackChangeEvent implements Parcelable { return this; } - public @NonNull Builder setBitrate(int value) { + /** + * Sets bitrate in bits per second. + * @param value the bitrate in bits per second. -1 indicates the value is unknown. + */ + public @NonNull Builder setBitrate(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) { checkNotUsed(); mBuilderFieldsSet |= 0x20; mBitrate = value; return this; } - public @NonNull Builder setTimeSincePlaybackCreatedMillis(long value) { + /** + * Sets timestamp since the creation in milliseconds. + * @param value the timestamp since the creation in milliseconds. + * -1 indicates the value is unknown. + */ + public @NonNull Builder setTimeSinceCreatedMillis(@IntRange(from = -1) long value) { checkNotUsed(); mBuilderFieldsSet |= 0x40; - mTimeSincePlaybackCreatedMillis = value; - return this; - } - - public @NonNull Builder setTrackType(@TrackType int value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x80; - mType = value; + mTimeSinceCreatedMillis = value; return this; } + /** + * Sets language code. + * @param value a two-letter ISO 639-1 language code. + */ public @NonNull Builder setLanguage(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x100; @@ -412,6 +482,11 @@ public final class TrackChangeEvent implements Parcelable { return this; } + /** + * Sets language region code. + * @param value an IETF BCP 47 optional language region subtag based on a two-letter country + * code. + */ public @NonNull Builder setLanguageRegion(@NonNull String value) { checkNotUsed(); mBuilderFieldsSet |= 0x200; @@ -419,28 +494,46 @@ public final class TrackChangeEvent implements Parcelable { return this; } - public @NonNull Builder setChannelCount(int value) { + /** + * Sets channel count. + * @param value the channel count. -1 indicates the value is unknown. + */ + public @NonNull Builder setChannelCount( + @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { checkNotUsed(); mBuilderFieldsSet |= 0x400; mChannelCount = value; return this; } - public @NonNull Builder setSampleRate(int value) { + /** + * Sets sample rate. + * @param value the sample rate. -1 indicates the value is unknown. + */ + public @NonNull Builder setSampleRate( + @IntRange(from = -1, to = Integer.MAX_VALUE) int value) { checkNotUsed(); mBuilderFieldsSet |= 0x800; mSampleRate = value; return this; } - public @NonNull Builder setWidth(int value) { + /** + * Sets video width. + * @param value the video width. -1 indicates the value is unknown. + */ + public @NonNull Builder setWidth(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) { checkNotUsed(); mBuilderFieldsSet |= 0x1000; mWidth = value; return this; } - public @NonNull Builder setHeight(int value) { + /** + * Sets video height. + * @param value the video height. -1 indicates the value is unknown. + */ + public @NonNull Builder setHeight(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) { checkNotUsed(); mBuilderFieldsSet |= 0x2000; mHeight = value; @@ -459,7 +552,7 @@ public final class TrackChangeEvent implements Parcelable { mSampleMimeType, mCodecName, mBitrate, - mTimeSincePlaybackCreatedMillis, + mTimeSinceCreatedMillis, mType, mLanguage, mLanguageRegion, diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index 66d579408db0..dc476b873786 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -73,8 +73,10 @@ interface ISessionManager { void setOnMediaKeyListener(in IOnMediaKeyListener listener); boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid); - void setCustomMediaKeyDispatcherForTesting(String name); - void setCustomSessionPolicyProviderForTesting(String name); + void setCustomMediaKeyDispatcher(String name); + void setCustomMediaSessionPolicyProvider(String name); + boolean hasCustomMediaKeyDispatcher(String componentName); + boolean hasCustomMediaSessionPolicyProvider(String componentName); int getSessionPolicies(in MediaSession.Token token); void setSessionPolicies(in MediaSession.Token token, int policies); } diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 13a3436569aa..8de5e42e93b2 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -958,9 +958,9 @@ public final class MediaSessionManager { * @hide */ @VisibleForTesting - public void setCustomMediaKeyDispatcherForTesting(@Nullable String name) { + public void setCustomMediaKeyDispatcher(@Nullable String name) { try { - mService.setCustomMediaKeyDispatcherForTesting(name); + mService.setCustomMediaKeyDispatcher(name); } catch (RemoteException e) { Log.e(TAG, "Failed to set custom media key dispatcher name", e); } @@ -968,22 +968,58 @@ public final class MediaSessionManager { /** * Set the component name for the custom - * {@link com.android.server.media.SessionPolicyProvider} class. Set to null to restore to the - * custom {@link com.android.server.media.SessionPolicyProvider} class name retrieved from the - * config value. + * {@link com.android.server.media.MediaSessionPolicyProvider} class. Set to null to restore to + * the custom {@link com.android.server.media.MediaSessionPolicyProvider} class name retrieved + * from the config value. * * @hide */ @VisibleForTesting - public void setCustomSessionPolicyProviderForTesting(@Nullable String name) { + public void setCustomMediaSessionPolicyProvider(@Nullable String name) { try { - mService.setCustomSessionPolicyProviderForTesting(name); + mService.setCustomMediaSessionPolicyProvider(name); } catch (RemoteException e) { Log.e(TAG, "Failed to set custom session policy provider name", e); } } /** + * Get the component name for the custom {@link com.android.server.media.MediaKeyDispatcher} + * class. + * + * @hide + */ + @VisibleForTesting + public boolean hasCustomMediaKeyDispatcher(@NonNull String componentName) { + Objects.requireNonNull(componentName, "componentName shouldn't be null"); + try { + return mService.hasCustomMediaKeyDispatcher(componentName); + } catch (RemoteException e) { + Log.e(TAG, "Failed to check if custom media key dispatcher with given component" + + " name exists", e); + } + return false; + } + + /** + * Get the component name for the custom + * {@link com.android.server.media.MediaSessionPolicyProvider} class. + * + * @hide + */ + @VisibleForTesting + public boolean hasCustomMediaSessionPolicyProvider(@NonNull String componentName) { + Objects.requireNonNull(componentName, "componentName shouldn't be null"); + try { + return mService.hasCustomMediaSessionPolicyProvider(componentName); + } catch (RemoteException e) { + Log.e(TAG, "Failed to check if custom media session policy provider with given" + + " component name exists", e); + } + return false; + } + + /** * Get session policies of the specified {@link MediaSession.Token}. * * @hide diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 740bc2dbeb43..c0185dcc4539 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -2525,7 +2525,9 @@ public final class TvInputManager { /** * Pauses TV program recording in the current recording session. * - * @param params A set of extra parameters which might be handled with this event. + * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped + * name, i.e. prefixed with a package name you own, so that different developers + * will not create conflicting keys. * {@link TvRecordingClient#pauseRecording(Bundle)}. */ void pauseRecording(@NonNull Bundle params) { @@ -2543,7 +2545,9 @@ public final class TvInputManager { /** * Resumes TV program recording in the current recording session. * - * @param params A set of extra parameters which might be handled with this event. + * @param params Domain-specific data for this request. Keys <em>must</em> be a scoped + * name, i.e. prefixed with a package name you own, so that different developers + * will not create conflicting keys. * {@link TvRecordingClient#resumeRecording(Bundle)}. */ void resumeRecording(@NonNull Bundle params) { diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp index c38d9194df44..c904ca2be00c 100644 --- a/media/java/android/media/tv/tunerresourcemanager/Android.bp +++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + filegroup { name: "framework-media-tv-tunerresourcemanager-sources-aidl", srcs: [ diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 4972529eb705..ce4550492740 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -1,3 +1,20 @@ +package { + default_applicable_licenses: ["frameworks_base_media_jni_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_base_media_jni_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + cc_library_shared { name: "libmedia_jni", @@ -64,6 +81,7 @@ cc_library_shared { "android.hardware.cas@1.0", "android.hardware.cas.native@1.0", "android.hardware.drm@1.3", + "android.hardware.drm@1.4", "android.hidl.memory@1.0", "android.hidl.token@1.0-utils", ], diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 0e8719eeb79c..73e1f7df89a1 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -37,6 +37,7 @@ #include <mediadrm/DrmUtils.h> #include <mediadrm/IDrmMetricsConsumer.h> #include <mediadrm/IDrm.h> +#include <utils/Vector.h> using ::android::os::PersistableBundle; namespace drm = ::android::hardware::drm; @@ -187,6 +188,11 @@ struct KeyStatusFields { jclass classId; }; +struct LogMessageFields { + jmethodID init; + jclass classId; +}; + struct fields_t { jfieldID context; jmethodID post_event; @@ -208,6 +214,7 @@ struct fields_t { jmethodID createFromParcelId; jclass parcelCreatorClassId; KeyStatusFields keyStatus; + LogMessageFields logMessage; }; static fields_t gFields; @@ -224,6 +231,19 @@ jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) { return result; } +jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessage> &logs) { + jclass clazz = gFields.arraylistClassId; + jobject arrayList = env->NewObject(clazz, gFields.arraylist.init); + clazz = gFields.logMessage.classId; + for (auto log: logs) { + jobject jLog = env->NewObject(clazz, gFields.logMessage.init, + static_cast<jlong>(log.timeMs), + static_cast<jint>(log.priority), + env->NewStringUTF(log.message.c_str())); + env->CallBooleanMethod(arrayList, gFields.arraylist.add, jLog); + } + return arrayList; +} } // namespace anonymous // ---------------------------------------------------------------------------- @@ -323,11 +343,56 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra, } } +jint MediaErrorToJavaError(status_t err) { +#define STATUS_CASE(status) \ + case status: \ + return J##status + + switch (err) { + STATUS_CASE(ERROR_DRM_UNKNOWN); + STATUS_CASE(ERROR_DRM_NO_LICENSE); + STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED); + STATUS_CASE(ERROR_DRM_RESOURCE_BUSY); + STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION); + STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED); + STATUS_CASE(ERROR_DRM_CANNOT_HANDLE); + STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY); + STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE); + STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE); + STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED); + STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING); + STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY); + STATUS_CASE(ERROR_DRM_GENERIC_OEM); + STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN); + STATUS_CASE(ERROR_DRM_INIT_DATA); + STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED); + STATUS_CASE(ERROR_DRM_LICENSE_PARSE); + STATUS_CASE(ERROR_DRM_LICENSE_POLICY); + STATUS_CASE(ERROR_DRM_LICENSE_RELEASE); + STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED); + STATUS_CASE(ERROR_DRM_LICENSE_RESTORE); + STATUS_CASE(ERROR_DRM_LICENSE_STATE); + STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK); + STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE); + STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG); + STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE); + STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY); + STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION); + STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE); + STATUS_CASE(ERROR_DRM_STORAGE_READ); + STATUS_CASE(ERROR_DRM_STORAGE_WRITE); + STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES); +#undef STATUS_CASE + } + return static_cast<jint>(err); +} + static void throwStateException(JNIEnv *env, const char *msg, status_t err) { ALOGE("Illegal state exception: %s (%d)", msg, err); + jint jerr = MediaErrorToJavaError(err); jobject exception = env->NewObject(gFields.stateException.classId, - gFields.stateException.init, static_cast<int>(err), + gFields.stateException.init, static_cast<int>(jerr), env->NewStringUTF(msg)); env->Throw(static_cast<jthrowable>(exception)); } @@ -357,43 +422,11 @@ static bool isSessionException(status_t err) { } static bool throwExceptionAsNecessary( - JNIEnv *env, status_t err, const char *msg = NULL) { - - const char *drmMessage = NULL; - - switch (err) { - case ERROR_DRM_UNKNOWN: - drmMessage = "General DRM error"; - break; - case ERROR_DRM_NO_LICENSE: - drmMessage = "No license"; - break; - case ERROR_DRM_LICENSE_EXPIRED: - drmMessage = "License expired"; - break; - case ERROR_DRM_SESSION_NOT_OPENED: - drmMessage = "Session not opened"; - break; - case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED: - drmMessage = "Not initialized"; - break; - case ERROR_DRM_DECRYPT: - drmMessage = "Decrypt error"; - break; - case ERROR_DRM_CANNOT_HANDLE: - drmMessage = "Invalid parameter or data format"; - break; - case ERROR_DRM_INVALID_STATE: - drmMessage = "Invalid state"; - break; - default: - break; - } - - String8 vendorMessage; - if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { - vendorMessage = String8::format("DRM vendor-defined error: %d", err); - drmMessage = vendorMessage.string(); + JNIEnv *env, const sp<IDrm> &drm, status_t err, const char *msg = NULL) { + std::string msgStr; + if (drm != NULL) { + msgStr = DrmUtils::GetExceptionMessage(err, msg, drm); + msg = msgStr.c_str(); } if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) { @@ -419,15 +452,6 @@ static bool throwExceptionAsNecessary( throwSessionException(env, msg, err); return true; } else if (err != OK) { - String8 errbuf; - if (drmMessage != NULL) { - if (msg == NULL) { - msg = drmMessage; - } else { - errbuf = String8::format("%s: %s", msg, drmMessage); - msg = errbuf.string(); - } - } throwStateException(env, msg, err); return true; } @@ -907,6 +931,10 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) { FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus"); gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V"); + + FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage"); + gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); + GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V"); } static void android_media_MediaDrm_native_setup( @@ -1021,7 +1049,7 @@ static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType, securityLevel, &isSupported); - if (throwExceptionAsNecessary(env, err, "Failed to query crypto scheme support")) { + if (throwExceptionAsNecessary(env, NULL, err, "Failed to query crypto scheme support")) { return false; } return isSupported; @@ -1044,7 +1072,7 @@ static jbyteArray android_media_MediaDrm_openSession( status_t err = drm->openSession(level, sessionId); - if (throwExceptionAsNecessary(env, err, "Failed to open session")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) { return NULL; } @@ -1063,7 +1091,7 @@ static void android_media_MediaDrm_closeSession( status_t err = drm->closeSession(sessionId); - throwExceptionAsNecessary(env, err, "Failed to close session"); + throwExceptionAsNecessary(env, drm, err, "Failed to close session"); } static jobject android_media_MediaDrm_getKeyRequest( @@ -1116,7 +1144,7 @@ static jobject android_media_MediaDrm_getKeyRequest( status_t err = drm->getKeyRequest(sessionId, initData, mimeType, keyType, optParams, request, defaultUrl, &keyRequestType); - if (throwExceptionAsNecessary(env, err, "Failed to get key request")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get key request")) { return NULL; } @@ -1186,7 +1214,7 @@ static jbyteArray android_media_MediaDrm_provideKeyResponse( status_t err = drm->provideKeyResponse(sessionId, response, keySetId); - if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to handle key response")) { return NULL; } return VectorToJByteArray(env, keySetId); @@ -1210,7 +1238,7 @@ static void android_media_MediaDrm_removeKeys( status_t err = drm->removeKeys(keySetId); - throwExceptionAsNecessary(env, err, "Failed to remove keys"); + throwExceptionAsNecessary(env, drm, err, "Failed to remove keys"); } static void android_media_MediaDrm_restoreKeys( @@ -1233,7 +1261,7 @@ static void android_media_MediaDrm_restoreKeys( status_t err = drm->restoreKeys(sessionId, keySetId); - throwExceptionAsNecessary(env, err, "Failed to restore keys"); + throwExceptionAsNecessary(env, drm, err, "Failed to restore keys"); } static jobject android_media_MediaDrm_queryKeyStatus( @@ -1249,7 +1277,7 @@ static jobject android_media_MediaDrm_queryKeyStatus( status_t err = drm->queryKeyStatus(sessionId, infoMap); - if (throwExceptionAsNecessary(env, err, "Failed to query key status")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to query key status")) { return NULL; } @@ -1279,7 +1307,7 @@ static jobject android_media_MediaDrm_getProvisionRequestNative( String8 certAuthority = JStringToString8(env, jcertAuthority); status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl); - if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get provision request")) { return NULL; } @@ -1334,7 +1362,7 @@ static jobject android_media_MediaDrm_provideProvisionResponseNative( env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey); } - throwExceptionAsNecessary(env, err, "Failed to handle provision response"); + throwExceptionAsNecessary(env, drm, err, "Failed to handle provision response"); return certificateObj; } @@ -1350,7 +1378,7 @@ static jobject android_media_MediaDrm_getSecureStops( status_t err = drm->getSecureStops(secureStops); - if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stops")) { return NULL; } @@ -1369,7 +1397,7 @@ static jobject android_media_MediaDrm_getSecureStopIds( status_t err = drm->getSecureStopIds(secureStopIds); - if (throwExceptionAsNecessary(env, err, "Failed to get secure stop Ids")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop Ids")) { return NULL; } @@ -1388,7 +1416,7 @@ static jbyteArray android_media_MediaDrm_getSecureStop( status_t err = drm->getSecureStop(JByteArrayToVector(env, ssid), secureStop); - if (throwExceptionAsNecessary(env, err, "Failed to get secure stop")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get secure stop")) { return NULL; } @@ -1407,7 +1435,7 @@ static void android_media_MediaDrm_releaseSecureStops( status_t err = drm->releaseSecureStops(ssRelease); - throwExceptionAsNecessary(env, err, "Failed to release secure stops"); + throwExceptionAsNecessary(env, drm, err, "Failed to release secure stops"); } static void android_media_MediaDrm_removeSecureStop( @@ -1420,7 +1448,7 @@ static void android_media_MediaDrm_removeSecureStop( status_t err = drm->removeSecureStop(JByteArrayToVector(env, ssid)); - throwExceptionAsNecessary(env, err, "Failed to remove secure stop"); + throwExceptionAsNecessary(env, drm, err, "Failed to remove secure stop"); } static void android_media_MediaDrm_removeAllSecureStops( @@ -1433,7 +1461,7 @@ static void android_media_MediaDrm_removeAllSecureStops( status_t err = drm->removeAllSecureStops(); - throwExceptionAsNecessary(env, err, "Failed to remove all secure stops"); + throwExceptionAsNecessary(env, drm, err, "Failed to remove all secure stops"); } @@ -1472,7 +1500,7 @@ static jint android_media_MediaDrm_getConnectedHdcpLevel(JNIEnv *env, status_t err = drm->getHdcpLevels(&connected, &max); - if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) { return gHdcpLevels.kHdcpLevelUnknown; } return HdcpLevelTojint(connected); @@ -1491,7 +1519,7 @@ static jint android_media_MediaDrm_getMaxHdcpLevel(JNIEnv *env, status_t err = drm->getHdcpLevels(&connected, &max); - if (throwExceptionAsNecessary(env, err, "Failed to get HDCP levels")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get HDCP levels")) { return gHdcpLevels.kHdcpLevelUnknown; } return HdcpLevelTojint(max); @@ -1508,7 +1536,7 @@ static jint android_media_MediaDrm_getOpenSessionCount(JNIEnv *env, uint32_t open = 0, max = 0; status_t err = drm->getNumberOfSessions(&open, &max); - if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) { return 0; } return open; @@ -1525,7 +1553,7 @@ static jint android_media_MediaDrm_getMaxSessionCount(JNIEnv *env, uint32_t open = 0, max = 0; status_t err = drm->getNumberOfSessions(&open, &max); - if (throwExceptionAsNecessary(env, err, "Failed to get number of sessions")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get number of sessions")) { return 0; } return max; @@ -1545,7 +1573,7 @@ static jint android_media_MediaDrm_getSecurityLevel(JNIEnv *env, status_t err = drm->getSecurityLevel(sessionId, &level); - if (throwExceptionAsNecessary(env, err, "Failed to get security level")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get security level")) { return gSecurityLevels.kSecurityLevelUnknown; } @@ -1577,7 +1605,7 @@ static jobject android_media_MediaDrm_getOfflineLicenseKeySetIds( status_t err = drm->getOfflineLicenseKeySetIds(keySetIds); - if (throwExceptionAsNecessary(env, err, "Failed to get offline key set Ids")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline key set Ids")) { return NULL; } @@ -1594,7 +1622,7 @@ static void android_media_MediaDrm_removeOfflineLicense( status_t err = drm->removeOfflineLicense(JByteArrayToVector(env, keySetId)); - throwExceptionAsNecessary(env, err, "Failed to remove offline license"); + throwExceptionAsNecessary(env, drm, err, "Failed to remove offline license"); } static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env, @@ -1611,7 +1639,7 @@ static jint android_media_MediaDrm_getOfflineLicenseState(JNIEnv *env, status_t err = drm->getOfflineLicenseState(keySetId, &state); - if (throwExceptionAsNecessary(env, err, "Failed to get offline license state")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get offline license state")) { return gOfflineLicenseStates.kOfflineLicenseStateUnknown; } @@ -1644,7 +1672,7 @@ static jstring android_media_MediaDrm_getPropertyString( status_t err = drm->getPropertyString(name, value); - if (throwExceptionAsNecessary(env, err, "Failed to get property")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) { return NULL; } @@ -1670,7 +1698,7 @@ static jbyteArray android_media_MediaDrm_getPropertyByteArray( status_t err = drm->getPropertyByteArray(name, value); - if (throwExceptionAsNecessary(env, err, "Failed to get property")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to get property")) { return NULL; } @@ -1702,7 +1730,7 @@ static void android_media_MediaDrm_setPropertyString( status_t err = drm->setPropertyString(name, value); - throwExceptionAsNecessary(env, err, "Failed to set property"); + throwExceptionAsNecessary(env, drm, err, "Failed to set property"); } static void android_media_MediaDrm_setPropertyByteArray( @@ -1730,7 +1758,7 @@ static void android_media_MediaDrm_setPropertyByteArray( status_t err = drm->setPropertyByteArray(name, value); - throwExceptionAsNecessary(env, err, "Failed to set property"); + throwExceptionAsNecessary(env, drm, err, "Failed to set property"); } static void android_media_MediaDrm_setCipherAlgorithmNative( @@ -1754,7 +1782,7 @@ static void android_media_MediaDrm_setCipherAlgorithmNative( status_t err = drm->setCipherAlgorithm(sessionId, algorithm); - throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm"); + throwExceptionAsNecessary(env, drm, err, "Failed to set cipher algorithm"); } static void android_media_MediaDrm_setMacAlgorithmNative( @@ -1778,7 +1806,7 @@ static void android_media_MediaDrm_setMacAlgorithmNative( status_t err = drm->setMacAlgorithm(sessionId, algorithm); - throwExceptionAsNecessary(env, err, "Failed to set mac algorithm"); + throwExceptionAsNecessary(env, drm, err, "Failed to set mac algorithm"); } @@ -1806,7 +1834,7 @@ static jbyteArray android_media_MediaDrm_encryptNative( status_t err = drm->encrypt(sessionId, keyId, input, iv, output); - if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to encrypt")) { return NULL; } @@ -1836,7 +1864,7 @@ static jbyteArray android_media_MediaDrm_decryptNative( Vector<uint8_t> output; status_t err = drm->decrypt(sessionId, keyId, input, iv, output); - if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to decrypt")) { return NULL; } @@ -1866,7 +1894,7 @@ static jbyteArray android_media_MediaDrm_signNative( status_t err = drm->sign(sessionId, keyId, message, signature); - if (throwExceptionAsNecessary(env, err, "Failed to sign")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) { return NULL; } @@ -1897,7 +1925,7 @@ static jboolean android_media_MediaDrm_verifyNative( status_t err = drm->verify(sessionId, keyId, message, signature, match); - throwExceptionAsNecessary(env, err, "Failed to verify"); + throwExceptionAsNecessary(env, drm, err, "Failed to verify"); return match; } @@ -1946,7 +1974,7 @@ static jbyteArray android_media_MediaDrm_signRSANative( status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature); - if (throwExceptionAsNecessary(env, err, "Failed to sign")) { + if (throwExceptionAsNecessary(env, drm, err, "Failed to sign")) { return NULL; } @@ -1993,7 +2021,23 @@ static void android_media_MediaDrm_setPlaybackId( playbackId = JStringToString8(env, jplaybackId); } status_t err = drm->setPlaybackId(sessionId, playbackId.c_str()); - throwExceptionAsNecessary(env, err, "Failed to set playbackId"); + throwExceptionAsNecessary(env, drm, err, "Failed to set playbackId"); +} + +static jobject android_media_MediaDrm_getLogMessages( + JNIEnv *env, jobject thiz) { + sp<IDrm> drm = GetDrm(env, thiz); + if (!CheckDrm(env, drm)) { + return NULL; + } + + Vector<drm::V1_4::LogMessage> logs; + status_t err = drm->getLogMessages(logs); + ALOGI("drm->getLogMessages %zu logs", logs.size()); + if (throwExceptionAsNecessary(env, drm, err, "Failed to get log messages")) { + return NULL; + } + return hidlLogMessagesToJavaList(env, logs); } static const JNINativeMethod gMethods[] = { @@ -2016,7 +2060,7 @@ static const JNINativeMethod gMethods[] = { { "closeSessionNative", "([B)V", (void *)android_media_MediaDrm_closeSession }, - { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)" + { "getKeyRequestNative", "([B[BLjava/lang/String;ILjava/util/HashMap;)" "Landroid/media/MediaDrm$KeyRequest;", (void *)android_media_MediaDrm_getKeyRequest }, @@ -2123,6 +2167,9 @@ static const JNINativeMethod gMethods[] = { { "setPlaybackId", "([BLjava/lang/String;)V", (void *)android_media_MediaDrm_setPlaybackId }, + + { "getLogMessages", "()Ljava/util/List;", + (void *)android_media_MediaDrm_getLogMessages }, }; int register_android_media_Drm(JNIEnv *env) { diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index b1f544cb2dbe..dc0793af2d17 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -28,6 +28,44 @@ namespace { +enum { + // TODO(b/180483929): use reverse jni e.g. android_media_MediaDrm_native_init + // KEEP IN SYNC with MediaDrm$ErrorCodes in MediaDrm.java! + JERROR_DRM_UNKNOWN = 0, + JERROR_DRM_NO_LICENSE = 1, + JERROR_DRM_LICENSE_EXPIRED = 2, + JERROR_DRM_RESOURCE_BUSY = 3, + JERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 4, + JERROR_DRM_SESSION_NOT_OPENED = 5, + JERROR_DRM_CANNOT_HANDLE = 6, + JERROR_DRM_INSUFFICIENT_SECURITY = 7, + JERROR_DRM_FRAME_TOO_LARGE = 8, + JERROR_DRM_SESSION_LOST_STATE = 9, + JERROR_DRM_CERTIFICATE_MALFORMED = 10, + JERROR_DRM_CERTIFICATE_MISSING = 11, + JERROR_DRM_CRYPTO_LIBRARY = 12, + JERROR_DRM_GENERIC_OEM = 13, + JERROR_DRM_GENERIC_PLUGIN = 14, + JERROR_DRM_INIT_DATA = 15, + JERROR_DRM_KEY_NOT_LOADED = 16, + JERROR_DRM_LICENSE_PARSE = 17, + JERROR_DRM_LICENSE_POLICY = 18, + JERROR_DRM_LICENSE_RELEASE = 19, + JERROR_DRM_LICENSE_REQUEST_REJECTED = 20, + JERROR_DRM_LICENSE_RESTORE = 21, + JERROR_DRM_LICENSE_STATE = 22, + JERROR_DRM_MEDIA_FRAMEWORK = 23, + JERROR_DRM_PROVISIONING_CERTIFICATE = 24, + JERROR_DRM_PROVISIONING_CONFIG = 25, + JERROR_DRM_PROVISIONING_PARSE = 26, + JERROR_DRM_PROVISIONING_RETRY = 27, + JERROR_DRM_RESOURCE_CONTENTION = 28, + JERROR_DRM_SECURE_STOP_RELEASE = 29, + JERROR_DRM_STORAGE_READ = 30, + JERROR_DRM_STORAGE_WRITE = 31, + JERROR_DRM_ZERO_SUBSAMPLES = 32, +}; + struct ListenerArgs { jbyteArray jSessionId; jbyteArray jData; @@ -98,6 +136,8 @@ private: DISALLOW_EVIL_CONSTRUCTORS(JDrm); }; +jint MediaErrorToJavaError(status_t err); + } // namespace android #endif // _ANDROID_MEDIA_DRM_H_ diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp index 40e4c54c2921..c2fc91d5cfea 100644 --- a/media/jni/audioeffect/Android.bp +++ b/media/jni/audioeffect/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_media_jni_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_media_jni_license"], +} + cc_library_shared { name: "libaudioeffect_jni", diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index 6141308a8fdb..7b498e027d1c 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -1,3 +1,22 @@ +package { + default_applicable_licenses: [ + "frameworks_base_media_jni_soundpool_license", + ], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_base_media_jni_soundpool_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} + tidy_errors = [ // https://clang.llvm.org/extra/clang-tidy/checks/list.html // For many categories, the checks are too many to specify individually. diff --git a/media/jni/soundpool/tests/Android.bp b/media/jni/soundpool/tests/Android.bp index 52f59ed69503..7d31c106f9c4 100644 --- a/media/jni/soundpool/tests/Android.bp +++ b/media/jni/soundpool/tests/Android.bp @@ -1,3 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_media_jni_soundpool_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: [ + "frameworks_base_media_jni_soundpool_license", + ], +} + cc_binary { name: "soundpool_stress", host_supported: false, diff --git a/media/lib/remotedisplay/Android.bp b/media/lib/remotedisplay/Android.bp index 5f4b930f350e..bfb0cb854be3 100644 --- a/media/lib/remotedisplay/Android.bp +++ b/media/lib/remotedisplay/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + java_sdk_library { name: "com.android.media.remotedisplay", srcs: ["java/**/*.java"], diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp index 3b2578754087..6504176eb6f1 100644 --- a/media/lib/signer/Android.bp +++ b/media/lib/signer/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + java_sdk_library { name: "com.android.mediadrm.signer", srcs: ["java/**/*.java"], diff --git a/media/lib/tvremote/Android.bp b/media/lib/tvremote/Android.bp index c5d14191c6c8..a58f677c3c30 100644 --- a/media/lib/tvremote/Android.bp +++ b/media/lib/tvremote/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + java_sdk_library { name: "com.android.media.tv.remoteprovider", srcs: ["java/**/*.java"], diff --git a/media/lib/tvremote/tests/Android.bp b/media/lib/tvremote/tests/Android.bp index f00eed070798..f02cfc393c81 100644 --- a/media/lib/tvremote/tests/Android.bp +++ b/media/lib/tvremote/tests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "TvRemoteTests", srcs: ["src/**/*.java"], diff --git a/media/mca/filterfw/Android.bp b/media/mca/filterfw/Android.bp index 0e0ecf331afc..ef3583f1a77f 100644 --- a/media/mca/filterfw/Android.bp +++ b/media/mca/filterfw/Android.bp @@ -13,6 +13,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_library_shared { name: "libfilterfw", diff --git a/media/mca/filterfw/native/Android.bp b/media/mca/filterfw/native/Android.bp index 7a8a6a18664e..7e4a34e8d934 100644 --- a/media/mca/filterfw/native/Android.bp +++ b/media/mca/filterfw/native/Android.bp @@ -16,6 +16,15 @@ //#################### // Build module libfilterfw_static +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_library_static { name: "libfilterfw_native", diff --git a/media/mca/filterpacks/Android.bp b/media/mca/filterpacks/Android.bp index 34fb27dd1663..b50df6eb572c 100644 --- a/media/mca/filterpacks/Android.bp +++ b/media/mca/filterpacks/Android.bp @@ -13,6 +13,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_library_static { name: "libfilterpack_base", srcs: [ diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.bp b/media/mca/samples/CameraEffectsRecordingSample/Android.bp index 96e81ab9b9cc..541660c1e4a2 100644 --- a/media/mca/samples/CameraEffectsRecordingSample/Android.bp +++ b/media/mca/samples/CameraEffectsRecordingSample/Android.bp @@ -15,6 +15,15 @@ // Build activity +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "CameraEffectsRecordingSample", srcs: ["**/*.java"], @@ -23,4 +32,3 @@ android_test { enabled: false, }, } - diff --git a/media/mca/tests/Android.bp b/media/mca/tests/Android.bp index 6b11dd9db7ba..f02b4c0a4bfb 100644 --- a/media/mca/tests/Android.bp +++ b/media/mca/tests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "CameraEffectsTests", libs: [ diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp index 2da45b6a78be..7acb8c744ba7 100644 --- a/media/native/midi/Android.bp +++ b/media/native/midi/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_library_shared { name: "libamidi", diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp index 25c34c3631dc..94a7a17638a5 100644 --- a/media/packages/BluetoothMidiService/Android.bp +++ b/media/packages/BluetoothMidiService/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_library { name: "BluetoothMidiLib", srcs: [ diff --git a/media/packages/BluetoothMidiService/tests/unit/Android.bp b/media/packages/BluetoothMidiService/tests/unit/Android.bp index fa4612bc22e7..67c7e4230f30 100644 --- a/media/packages/BluetoothMidiService/tests/unit/Android.bp +++ b/media/packages/BluetoothMidiService/tests/unit/Android.bp @@ -14,6 +14,15 @@ // limitations under the License. // +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "BluetoothMidiTests", srcs: ["src/**/*.java"], diff --git a/media/tests/AudioPolicyTest/Android.bp b/media/tests/AudioPolicyTest/Android.bp index ed3383752695..95d1c6ccb67c 100644 --- a/media/tests/AudioPolicyTest/Android.bp +++ b/media/tests/AudioPolicyTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "audiopolicytest", srcs: ["**/*.java"], diff --git a/media/tests/CameraBrowser/Android.bp b/media/tests/CameraBrowser/Android.bp index 8e3ca1943b17..1408640a6b0d 100644 --- a/media/tests/CameraBrowser/Android.bp +++ b/media/tests/CameraBrowser/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "CameraBrowser", srcs: ["**/*.java"], diff --git a/media/tests/EffectsTest/Android.bp b/media/tests/EffectsTest/Android.bp index 214e8c02f742..644e453b8956 100644 --- a/media/tests/EffectsTest/Android.bp +++ b/media/tests/EffectsTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "EffectsTest", srcs: ["**/*.java"], diff --git a/media/tests/MediaDump/Android.bp b/media/tests/MediaDump/Android.bp index 0eba8b24f6cd..f54b97a06558 100644 --- a/media/tests/MediaDump/Android.bp +++ b/media/tests/MediaDump/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_app { name: "MediaDump", // Only compile source java files in this apk. diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp index 3f1954a0874a..48d56d898138 100644 --- a/media/tests/MediaFrameworkTest/Android.bp +++ b/media/tests/MediaFrameworkTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "mediaframeworktest", srcs: ["**/*.java"], diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp index a439b79fa2f0..d41bc02906ab 100644 --- a/media/tests/MediaRouter/Android.bp +++ b/media/tests/MediaRouter/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "mediaroutertest", @@ -17,4 +26,4 @@ android_test { platform_apis: true, certificate: "platform", -}
\ No newline at end of file +} diff --git a/media/tests/MtpTests/Android.bp b/media/tests/MtpTests/Android.bp index 7d2c7c693fa5..3016873e1de8 100644 --- a/media/tests/MtpTests/Android.bp +++ b/media/tests/MtpTests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "MtpTests", srcs: ["**/*.java"], diff --git a/media/tests/ScoAudioTest/Android.bp b/media/tests/ScoAudioTest/Android.bp index ad2b91716145..f8a893bf7f2c 100644 --- a/media/tests/ScoAudioTest/Android.bp +++ b/media/tests/ScoAudioTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "scoaudiotest", platform_apis: true, diff --git a/media/tests/SoundPoolTest/Android.bp b/media/tests/SoundPoolTest/Android.bp index 473f531f675b..0a50106d52c8 100644 --- a/media/tests/SoundPoolTest/Android.bp +++ b/media/tests/SoundPoolTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "SoundPoolTest", srcs: ["**/*.java"], diff --git a/media/tests/TunerTest/Android.bp b/media/tests/TunerTest/Android.bp index 5c3e9ab9812f..8e8816cee876 100644 --- a/media/tests/TunerTest/Android.bp +++ b/media/tests/TunerTest/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + android_test { name: "mediatunertest", diff --git a/media/tests/audiotests/Android.bp b/media/tests/audiotests/Android.bp index 5db0ab0cde6d..c52c0336979c 100644 --- a/media/tests/audiotests/Android.bp +++ b/media/tests/audiotests/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_test { name: "shared_mem_test", gtest: false, diff --git a/media/tests/players/Android.bp b/media/tests/players/Android.bp index 23c5f04c93a6..3b6df707badb 100644 --- a/media/tests/players/Android.bp +++ b/media/tests/players/Android.bp @@ -12,6 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + cc_test_library { name: "invoke_mock_media_player", srcs: ["invoke_mock_media_player.cpp"], |