Move DRM error code assignment into DefaultDrmSession

PiperOrigin-RevId: 384280087
This commit is contained in:
aquilescanta 2021-07-12 19:36:05 +01:00 committed by Oliver Woodman
parent 8451be1b0b
commit cdaf3e4e99
3 changed files with 95 additions and 82 deletions

View File

@ -19,10 +19,6 @@ import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; 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.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Looper; 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.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Player.RepeatMode; import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.analytics.AnalyticsCollector; 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.DrmSession;
import com.google.android.exoplayer2.drm.UnsupportedDrmException;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaPeriod;
@ -590,27 +584,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
playbackInfo = playbackInfo.copyWithPlaybackError(e); playbackInfo = playbackInfo.copyWithPlaybackError(e);
} }
} catch (DrmSession.DrmSessionException e) { } catch (DrmSession.DrmSessionException e) {
@Nullable Throwable cause = e.getCause(); handleIoException(e, e.errorCode);
@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);
} catch (FileDataSource.FileDataSourceException e) { } catch (FileDataSource.FileDataSourceException e) {
@Nullable Throwable cause = e.getCause(); @Nullable Throwable cause = e.getCause();
@ErrorCode int errorCode; @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) @RequiresApi(21)
private static final class PlatformOperationsWrapperV21 { private static final class PlatformOperationsWrapperV21 {
@ -3113,28 +3073,5 @@ import java.util.concurrent.atomic.AtomicBoolean;
public static boolean isPermissionError(@Nullable Throwable e) { public static boolean isPermissionError(@Nullable Throwable e) {
return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES; 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;
}
} }
} }

View File

@ -19,6 +19,9 @@ import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.DeniedByServerException;
import android.media.MediaDrm;
import android.media.MediaDrmResetException;
import android.media.NotProvisionedException; import android.media.NotProvisionedException;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
@ -26,6 +29,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.DoNotInline;
import androidx.annotation.GuardedBy; import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; 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. * Called by a session when it fails to perform a provisioning operation.
* *
* @param error The error that occurred. * @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. */ /** Called by a session when it successfully completes a provisioning operation. */
void onProvisionCompleted(); void onProvisionCompleted();
@ -236,8 +242,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
} }
public void onProvisionError(Exception error) { public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) {
onError(error); onError(error, thrownByExoMediaDrm);
} }
// DrmSession implementation. // DrmSession implementation.
@ -360,7 +366,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} catch (NotProvisionedException e) { } catch (NotProvisionedException e) {
provisioningManager.provisionRequired(this); provisioningManager.provisionRequired(this);
} catch (Exception e) { } catch (Exception e) {
onError(e); onError(e, /* thrownByExoMediaDrm= */ true);
} }
return false; return false;
@ -374,14 +380,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
currentProvisionRequest = null; currentProvisionRequest = null;
if (response instanceof Exception) { if (response instanceof Exception) {
provisioningManager.onProvisionError((Exception) response); provisioningManager.onProvisionError((Exception) response, /* thrownByExoMediaDrm= */ false);
return; return;
} }
try { try {
mediaDrm.provideProvisionResponse((byte[]) response); mediaDrm.provideProvisionResponse((byte[]) response);
} catch (Exception e) { } catch (Exception e) {
provisioningManager.onProvisionError(e); provisioningManager.onProvisionError(e, /* thrownByExoMediaDrm= */ true);
return; return;
} }
@ -410,7 +416,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
+ licenseDurationRemainingSec); + licenseDurationRemainingSec);
postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
} else if (licenseDurationRemainingSec <= 0) { } else if (licenseDurationRemainingSec <= 0) {
onError(new KeysExpiredException()); onError(new KeysExpiredException(), /* thrownByExoMediaDrm= */ false);
} else { } else {
state = STATE_OPENED_WITH_KEYS; state = STATE_OPENED_WITH_KEYS;
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored); dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored);
@ -438,7 +444,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId); mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
onError(e); onError(e, /* thrownByExoMediaDrm= */ true);
} }
return false; return false;
} }
@ -458,7 +464,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
Util.castNonNull(requestHandler) Util.castNonNull(requestHandler)
.post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry); .post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry);
} catch (Exception e) { } catch (Exception e) {
onKeysError(e); onKeysError(e, /* thrownByExoMediaDrm= */ true);
} }
} }
@ -470,7 +476,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
currentKeyRequest = null; currentKeyRequest = null;
if (response instanceof Exception) { if (response instanceof Exception) {
onKeysError((Exception) response); onKeysError((Exception) response, /* thrownByExoMediaDrm= */ false);
return; return;
} }
@ -492,7 +498,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded); dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
} }
} catch (Exception e) { } 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) { if (e instanceof NotProvisionedException) {
provisioningManager.provisionRequired(this); provisioningManager.provisionRequired(this);
} else { } else {
onError(e); onError(e, thrownByExoMediaDrm);
} }
} }
private void onError(final Exception e) { private void onError(Exception e, boolean thrownByExoMediaDrm) {
// TODO(internal b/184262323): Add an argument here which takes the error code from the caller. lastException =
lastException = new DrmSessionException(e, PlaybackException.ERROR_CODE_DRM_UNSPECIFIED); new DrmSessionException(e, getErrorCodeForMediaDrmException(e, thrownByExoMediaDrm));
Log.e(TAG, "DRM session error", e); Log.e(TAG, "DRM session error", e);
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e)); dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
if (state != STATE_OPENED_WITH_KEYS) { 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. // Internal classes.
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
@ -678,4 +713,45 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
this.request = request; 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;
}
}
} }

View File

@ -876,14 +876,14 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
} }
@Override @Override
public void onProvisionError(Exception error) { public void onProvisionError(Exception error, boolean thrownByExoMediaDrm) {
provisioningSession = null; provisioningSession = null;
ImmutableList<DefaultDrmSession> sessionsToNotify = ImmutableList<DefaultDrmSession> sessionsToNotify =
ImmutableList.copyOf(sessionsAwaitingProvisioning); ImmutableList.copyOf(sessionsAwaitingProvisioning);
// Clear the list before calling onProvisionError in case provisioning is re-requested. // Clear the list before calling onProvisionError in case provisioning is re-requested.
sessionsAwaitingProvisioning.clear(); sessionsAwaitingProvisioning.clear();
for (DefaultDrmSession session : sessionsToNotify) { for (DefaultDrmSession session : sessionsToNotify) {
session.onProvisionError(error); session.onProvisionError(error, thrownByExoMediaDrm);
} }
} }