From cdaf3e4e99d41228fc72ee9a8e14feb64f6d17b3 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 12 Jul 2021 19:36:05 +0100 Subject: [PATCH] Move DRM error code assignment into DefaultDrmSession PiperOrigin-RevId: 384280087 --- .../exoplayer2/ExoPlayerImplInternal.java | 65 +---------- .../exoplayer2/drm/DefaultDrmSession.java | 108 +++++++++++++++--- .../drm/DefaultDrmSessionManager.java | 4 +- 3 files changed, 95 insertions(+), 82 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 37ea0d6c0c..f8abfbe894 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -19,10 +19,6 @@ import static com.google.android.exoplayer2.util.Util.castNonNull; import static java.lang.Math.max; import static java.lang.Math.min; -import android.media.DeniedByServerException; -import android.media.MediaDrm; -import android.media.MediaDrmResetException; -import android.media.NotProvisionedException; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -43,9 +39,7 @@ import com.google.android.exoplayer2.Player.PlayWhenReadyChangeReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.analytics.AnalyticsCollector; -import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DrmSession; -import com.google.android.exoplayer2.drm.UnsupportedDrmException; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.MediaPeriod; @@ -590,27 +584,7 @@ import java.util.concurrent.atomic.AtomicBoolean; playbackInfo = playbackInfo.copyWithPlaybackError(e); } } catch (DrmSession.DrmSessionException e) { - @Nullable Throwable cause = e.getCause(); - @ErrorCode int errorCode; - if (Util.SDK_INT >= 21 && PlatformOperationsWrapperV21.isMediaDrmStateException(cause)) { - errorCode = PlatformOperationsWrapperV21.mediaDrmStateExceptionToErrorCode(cause); - } else if (Util.SDK_INT >= 23 - && PlatformOperationsWrapperV23.isMediaDrmResetException(cause)) { - errorCode = PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; - } else if (Util.SDK_INT >= 18 - && PlatformOperationsWrapperV18.isNotProvisionedException(cause)) { - errorCode = PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED; - } else if (Util.SDK_INT >= 18 - && PlatformOperationsWrapperV18.isDeniedByServerException(cause)) { - errorCode = PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED; - } else if (cause instanceof UnsupportedDrmException) { - errorCode = PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED; - } else if (cause instanceof DefaultDrmSessionManager.MissingSchemeDataException) { - errorCode = PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR; - } else { - errorCode = PlaybackException.ERROR_CODE_DRM_UNSPECIFIED; - } - handleIoException(e, errorCode); + handleIoException(e, e.errorCode); } catch (FileDataSource.FileDataSourceException e) { @Nullable Throwable cause = e.getCause(); @ErrorCode int errorCode; @@ -3092,20 +3066,6 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - @RequiresApi(18) - private static final class PlatformOperationsWrapperV18 { - - @DoNotInline - public static boolean isNotProvisionedException(@Nullable Throwable throwable) { - return throwable instanceof NotProvisionedException; - } - - @DoNotInline - public static boolean isDeniedByServerException(@Nullable Throwable throwable) { - return throwable instanceof DeniedByServerException; - } - } - @RequiresApi(21) private static final class PlatformOperationsWrapperV21 { @@ -3113,28 +3073,5 @@ import java.util.concurrent.atomic.AtomicBoolean; public static boolean isPermissionError(@Nullable Throwable e) { return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES; } - - @DoNotInline - public static boolean isMediaDrmStateException(@Nullable Throwable throwable) { - return throwable instanceof MediaDrm.MediaDrmStateException; - } - - @DoNotInline - @ErrorCode - public static int mediaDrmStateExceptionToErrorCode(Throwable throwable) { - @Nullable - String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) throwable).getDiagnosticInfo(); - int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); - return C.getErrorCodeForMediaDrmErrorCode(drmErrorCode); - } - } - - @RequiresApi(23) - private static final class PlatformOperationsWrapperV23 { - - @DoNotInline - public static boolean isMediaDrmResetException(@Nullable Throwable throwable) { - return throwable instanceof MediaDrmResetException; - } } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java index d6a28ed2e8..1f716a62f5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java @@ -19,6 +19,9 @@ import static com.google.android.exoplayer2.util.Assertions.checkState; import static java.lang.Math.min; import android.annotation.SuppressLint; +import android.media.DeniedByServerException; +import android.media.MediaDrm; +import android.media.MediaDrmResetException; import android.media.NotProvisionedException; import android.os.Handler; import android.os.HandlerThread; @@ -26,6 +29,7 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Pair; +import androidx.annotation.DoNotInline; import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -83,8 +87,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; * Called by a session when it fails to perform a provisioning operation. * * @param error The error that occurred. + * @param thrownByExoMediaDrm Whether the error originated in an {@link ExoMediaDrm} operation. + * False when the error originated in the provisioning request. */ - void onProvisionError(Exception error); + void onProvisionError(Exception error, boolean thrownByExoMediaDrm); /** Called by a session when it successfully completes a provisioning operation. */ void onProvisionCompleted(); @@ -236,8 +242,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } } - public void onProvisionError(Exception error) { - onError(error); + public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) { + onError(error, thrownByExoMediaDrm); } // DrmSession implementation. @@ -360,7 +366,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } catch (NotProvisionedException e) { provisioningManager.provisionRequired(this); } catch (Exception e) { - onError(e); + onError(e, /* thrownByExoMediaDrm= */ true); } return false; @@ -374,14 +380,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; currentProvisionRequest = null; if (response instanceof Exception) { - provisioningManager.onProvisionError((Exception) response); + provisioningManager.onProvisionError((Exception) response, /* thrownByExoMediaDrm= */ false); return; } try { mediaDrm.provideProvisionResponse((byte[]) response); } catch (Exception e) { - provisioningManager.onProvisionError(e); + provisioningManager.onProvisionError(e, /* thrownByExoMediaDrm= */ true); return; } @@ -410,7 +416,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; + licenseDurationRemainingSec); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); } else if (licenseDurationRemainingSec <= 0) { - onError(new KeysExpiredException()); + onError(new KeysExpiredException(), /* thrownByExoMediaDrm= */ false); } else { state = STATE_OPENED_WITH_KEYS; dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored); @@ -438,7 +444,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId); return true; } catch (Exception e) { - onError(e); + onError(e, /* thrownByExoMediaDrm= */ true); } return false; } @@ -458,7 +464,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; Util.castNonNull(requestHandler) .post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry); } catch (Exception e) { - onKeysError(e); + onKeysError(e, /* thrownByExoMediaDrm= */ true); } } @@ -470,7 +476,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; currentKeyRequest = null; if (response instanceof Exception) { - onKeysError((Exception) response); + onKeysError((Exception) response, /* thrownByExoMediaDrm= */ false); return; } @@ -492,7 +498,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded); } } catch (Exception e) { - onKeysError(e); + onKeysError(e, /* thrownByExoMediaDrm= */ true); } } @@ -503,17 +509,17 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } } - private void onKeysError(Exception e) { + private void onKeysError(Exception e, boolean thrownByExoMediaDrm) { if (e instanceof NotProvisionedException) { provisioningManager.provisionRequired(this); } else { - onError(e); + onError(e, thrownByExoMediaDrm); } } - private void onError(final Exception e) { - // TODO(internal b/184262323): Add an argument here which takes the error code from the caller. - lastException = new DrmSessionException(e, PlaybackException.ERROR_CODE_DRM_UNSPECIFIED); + private void onError(Exception e, boolean thrownByExoMediaDrm) { + lastException = + new DrmSessionException(e, getErrorCodeForMediaDrmException(e, thrownByExoMediaDrm)); Log.e(TAG, "DRM session error", e); dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e)); if (state != STATE_OPENED_WITH_KEYS) { @@ -533,6 +539,35 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } } + @PlaybackException.ErrorCode + private static int getErrorCodeForMediaDrmException( + Exception exception, boolean thrownByExoMediaDrm) { + if (Util.SDK_INT >= 21 && PlatformOperationsWrapperV21.isMediaDrmStateException(exception)) { + return PlatformOperationsWrapperV21.mediaDrmStateExceptionToErrorCode(exception); + } else if (Util.SDK_INT >= 23 + && PlatformOperationsWrapperV23.isMediaDrmResetException(exception)) { + return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; + } else if (Util.SDK_INT >= 18 + && PlatformOperationsWrapperV18.isNotProvisionedException(exception)) { + return PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED; + } else if (Util.SDK_INT >= 18 + && PlatformOperationsWrapperV18.isDeniedByServerException(exception)) { + return PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED; + } else if (exception instanceof UnsupportedDrmException) { + return PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED; + } else if (exception instanceof DefaultDrmSessionManager.MissingSchemeDataException) { + return PlaybackException.ERROR_CODE_DRM_CONTENT_ERROR; + } else if (exception instanceof KeysExpiredException) { + return PlaybackException.ERROR_CODE_DRM_LICENSE_EXPIRED; + } else if (thrownByExoMediaDrm) { + // A MediaDrm exception was thrown but it was impossible to determine the cause. Because no + // better diagnosis tools were provided, we treat this as a system error. + return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR; + } else { + return PlaybackException.ERROR_CODE_DRM_UNSPECIFIED; + } + } + // Internal classes. @SuppressLint("HandlerLeak") @@ -678,4 +713,45 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; this.request = request; } } + + @RequiresApi(18) + private static final class PlatformOperationsWrapperV18 { + + @DoNotInline + public static boolean isNotProvisionedException(@Nullable Throwable throwable) { + return throwable instanceof NotProvisionedException; + } + + @DoNotInline + public static boolean isDeniedByServerException(@Nullable Throwable throwable) { + return throwable instanceof DeniedByServerException; + } + } + + @RequiresApi(21) + private static final class PlatformOperationsWrapperV21 { + + @DoNotInline + public static boolean isMediaDrmStateException(@Nullable Throwable throwable) { + return throwable instanceof MediaDrm.MediaDrmStateException; + } + + @DoNotInline + @PlaybackException.ErrorCode + public static int mediaDrmStateExceptionToErrorCode(Throwable throwable) { + @Nullable + String diagnosticsInfo = ((MediaDrm.MediaDrmStateException) throwable).getDiagnosticInfo(); + int drmErrorCode = Util.getErrorCodeFromPlatformDiagnosticsInfo(diagnosticsInfo); + return C.getErrorCodeForMediaDrmErrorCode(drmErrorCode); + } + } + + @RequiresApi(23) + private static final class PlatformOperationsWrapperV23 { + + @DoNotInline + public static boolean isMediaDrmResetException(@Nullable Throwable throwable) { + return throwable instanceof MediaDrmResetException; + } + } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index 9b4b290459..3f9ab764c6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -876,14 +876,14 @@ public class DefaultDrmSessionManager implements DrmSessionManager { } @Override - public void onProvisionError(Exception error) { + public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) { provisioningSession = null; ImmutableList sessionsToNotify = ImmutableList.copyOf(sessionsAwaitingProvisioning); // Clear the list before calling onProvisionError in case provisioning is re-requested. sessionsAwaitingProvisioning.clear(); for (DefaultDrmSession session : sessionsToNotify) { - session.onProvisionError(error); + session.onProvisionError(error, thrownByExoMediaDrm); } }