Skip to content

Commit

Permalink
Add workarounds for NoSuchMethodError from DRM framework exceptions
Browse files Browse the repository at this point in the history
Issue: androidx/media#1145

#minor-release

PiperOrigin-RevId: 613573868
  • Loading branch information
icbaker authored and Copybara-Service committed Mar 7, 2024
1 parent 0a5ebb0 commit 36df880
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 30 deletions.
Expand Up @@ -402,8 +402,13 @@ private boolean openInternal() {
return true;
} catch (NotProvisionedException e) {
provisioningManager.provisionRequired(this);
} catch (Exception e) {
onError(e, DrmUtil.ERROR_SOURCE_EXO_MEDIA_DRM);
} catch (Exception | NoSuchMethodError e) {
// Work around b/291440132.
if (DrmUtil.isFailureToConstructNotProvisionedException(e)) {
provisioningManager.provisionRequired(this);
} else {
onError(e, DrmUtil.ERROR_SOURCE_EXO_MEDIA_DRM);
}
}

return false;
Expand Down Expand Up @@ -480,7 +485,7 @@ private boolean restoreKeys() {
try {
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
return true;
} catch (Exception e) {
} catch (Exception | NoSuchMethodError e) {
onError(e, DrmUtil.ERROR_SOURCE_EXO_MEDIA_DRM);
}
return false;
Expand All @@ -500,7 +505,7 @@ private void postKeyRequest(byte[] scope, int type, boolean allowRetry) {
currentKeyRequest = mediaDrm.getKeyRequest(scope, schemeDatas, type, keyRequestParameters);
Util.castNonNull(requestHandler)
.post(MSG_KEYS, Assertions.checkNotNull(currentKeyRequest), allowRetry);
} catch (Exception e) {
} catch (Exception | NoSuchMethodError e) {
onKeysError(e, /* thrownByExoMediaDrm= */ true);
}
}
Expand All @@ -512,8 +517,8 @@ private void onKeyResponse(Object request, Object response) {
}
currentKeyRequest = null;

if (response instanceof Exception) {
onKeysError((Exception) response, /* thrownByExoMediaDrm= */ false);
if (response instanceof Exception || response instanceof NoSuchMethodError) {
onKeysError((Throwable) response, /* thrownByExoMediaDrm= */ false);
return;
}

Expand All @@ -534,7 +539,7 @@ private void onKeyResponse(Object request, Object response) {
state = STATE_OPENED_WITH_KEYS;
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
}
} catch (Exception e) {
} catch (Exception | NoSuchMethodError e) {
onKeysError(e, /* thrownByExoMediaDrm= */ true);
}
}
Expand All @@ -546,8 +551,12 @@ private void onKeysRequired() {
}
}

private void onKeysError(Exception e, boolean thrownByExoMediaDrm) {
if (e instanceof NotProvisionedException) {
/**
* @param e Must be an instance of either {@link Exception} or {@link Error}.
*/
private void onKeysError(Throwable e, boolean thrownByExoMediaDrm) {
if (e instanceof NotProvisionedException
|| DrmUtil.isFailureToConstructNotProvisionedException(e)) {
provisioningManager.provisionRequired(this);
} else {
onError(
Expand All @@ -558,11 +567,24 @@ private void onKeysError(Exception e, boolean thrownByExoMediaDrm) {
}
}

private void onError(Exception e, @DrmUtil.ErrorSource int errorSource) {
/**
* @param e Must be an instance of either {@link Exception} or {@link Error}.
*/
private void onError(Throwable e, @DrmUtil.ErrorSource int errorSource) {
lastException =
new DrmSessionException(e, DrmUtil.getErrorCodeForMediaDrmException(e, errorSource));
Log.e(TAG, "DRM session error", e);
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
if (e instanceof Exception) {
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError((Exception) e));
} else if (e instanceof Error) {
// Re-throw all Error types except a NoSuchMethodError caused by b/291440132.
if (!DrmUtil.isFailureToConstructResourceBusyException(e)
&& !DrmUtil.isFailureToConstructNotProvisionedException(e)) {
throw (Error) e;
}
} else {
throw new IllegalStateException("Unexpected Throwable subclass", e);
}
if (state != STATE_OPENED_WITH_KEYS) {
state = STATE_ERROR;
}
Expand Down
Expand Up @@ -658,8 +658,12 @@ private DefaultDrmSession createAndAcquireSessionWithRetry(
}

private static boolean acquisitionFailedIndicatingResourceShortage(DrmSession session) {
return session.getState() == DrmSession.STATE_ERROR
&& checkNotNull(session.getError()).getCause() instanceof ResourceBusyException;
if (session.getState() != DrmSession.STATE_ERROR) {
return false;
}
@Nullable Throwable cause = checkNotNull(session.getError()).getCause();
return cause instanceof ResourceBusyException
|| DrmUtil.isFailureToConstructResourceBusyException(cause);
}

/**
Expand Down
Expand Up @@ -25,6 +25,7 @@
import android.media.MediaDrm;
import android.media.MediaDrmResetException;
import android.media.NotProvisionedException;
import android.media.ResourceBusyException;
import androidx.annotation.DoNotInline;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -81,12 +82,13 @@ public final class DrmUtil {
* exception.
*/
public static @PlaybackException.ErrorCode int getErrorCodeForMediaDrmException(
Exception exception, @ErrorSource int errorSource) {
Throwable exception, @ErrorSource int errorSource) {
if (Util.SDK_INT >= 21 && Api21.isMediaDrmStateException(exception)) {
return Api21.mediaDrmStateExceptionToErrorCode(exception);
} else if (Util.SDK_INT >= 23 && Api23.isMediaDrmResetException(exception)) {
return PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR;
} else if (exception instanceof NotProvisionedException) {
} else if (exception instanceof NotProvisionedException
|| isFailureToConstructNotProvisionedException(exception)) {
return PlaybackException.ERROR_CODE_DRM_PROVISIONING_FAILED;
} else if (exception instanceof DeniedByServerException) {
return PlaybackException.ERROR_CODE_DRM_DEVICE_REVOKED;
Expand All @@ -110,6 +112,28 @@ public final class DrmUtil {
}
}

/**
* Returns true if {@code e} represents a failure to construct a {@link NotProvisionedException}.
* See b/291440132.
*/
public static boolean isFailureToConstructNotProvisionedException(@Nullable Throwable e) {
return Util.SDK_INT == 34
&& e instanceof NoSuchMethodError
&& e.getMessage() != null
&& e.getMessage().contains("Landroid/media/NotProvisionedException;.<init>(");
}

/**
* Returns true if {@code e} represents a failure to construct a {@link ResourceBusyException}.
* See b/291440132.
*/
public static boolean isFailureToConstructResourceBusyException(@Nullable Throwable e) {
return Util.SDK_INT == 34
&& e instanceof NoSuchMethodError
&& e.getMessage() != null
&& e.getMessage().contains("Landroid/media/ResourceBusyException;.<init>(");
}

// Internal classes.

@RequiresApi(21)
Expand Down

0 comments on commit 36df880

Please sign in to comment.