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: #1145

#minor-release

PiperOrigin-RevId: 613573868
  • Loading branch information
icbaker authored and copybara-github committed Mar 7, 2024
1 parent f02dc8e commit a604600
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 30 deletions.
4 changes: 4 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
* Metadata:
* Image:
* DRM:
* Work around a `NoSuchMethodError` which can be thrown by the `MediaDrm`
framework instead of `ResourceBusyException` or
`NotProvisionedException` on some Android 14 devices
([#1145](https://github.com/androidx/media/issues/1145)).
* DataSource:
* Implement support for `android.resource://package/id` raw resource URIs
where `package` is different to the package of the current application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,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 @@ -472,7 +477,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 @@ -492,7 +497,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 @@ -504,8 +509,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 @@ -526,7 +531,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 @@ -538,8 +543,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 @@ -550,11 +559,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
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,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
Original file line number Diff line number Diff line change
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 @@ -75,12 +76,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 @@ -104,6 +106,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
Loading

0 comments on commit a604600

Please sign in to comment.