Add workarounds for NoSuchMethodError from DRM framework exceptions

Issue: androidx/media#1145

#minor-release

PiperOrigin-RevId: 613573868
This commit is contained in:
ibaker 2024-03-07 07:13:01 -08:00 committed by Copybara-Service
parent f02dc8e528
commit a604600126
6 changed files with 267 additions and 30 deletions

View File

@ -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.

View File

@ -394,8 +394,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
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;
@ -472,7 +477,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
try {
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
return true;
} catch (Exception e) {
} catch (Exception | NoSuchMethodError e) {
onError(e, DrmUtil.ERROR_SOURCE_EXO_MEDIA_DRM);
}
return false;
@ -492,7 +497,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
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);
}
}
@ -504,8 +509,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
currentKeyRequest = null;
if (response instanceof Exception) {
onKeysError((Exception) response, /* thrownByExoMediaDrm= */ false);
if (response instanceof Exception || response instanceof NoSuchMethodError) {
onKeysError((Throwable) response, /* thrownByExoMediaDrm= */ false);
return;
}
@ -526,7 +531,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
state = STATE_OPENED_WITH_KEYS;
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
}
} catch (Exception e) {
} catch (Exception | NoSuchMethodError e) {
onKeysError(e, /* thrownByExoMediaDrm= */ true);
}
}
@ -538,8 +543,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
}
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(
@ -550,11 +559,24 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
}
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;
}

View File

@ -655,8 +655,12 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
}
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);
}
/**

View File

@ -25,6 +25,7 @@ import android.media.DeniedByServerException;
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;
@ -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;
@ -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)

View File

@ -40,6 +40,7 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
/** Tests for {@link DefaultDrmSessionManager} and {@link DefaultDrmSession}. */
@ -258,6 +259,21 @@ public class DefaultDrmSessionManagerTest {
@Test(timeout = 10_000)
public void maxConcurrentSessionsExceeded_allKeepAliveSessionsEagerlyReleased() throws Exception {
maxConcurrentSessionsExceededAllKeepAliveSessionsEagerlyReleased(
/* throwNoSuchMethodErrorForResourceBusy= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test(timeout = 10_000)
public void maxConcurrentSessionsExceeded_allKeepAliveSessionsEagerlyReleased_noSuchMethodError()
throws Exception {
maxConcurrentSessionsExceededAllKeepAliveSessionsEagerlyReleased(
/* throwNoSuchMethodErrorForResourceBusy= */ true);
}
private static void maxConcurrentSessionsExceededAllKeepAliveSessionsEagerlyReleased(
boolean throwNoSuchMethodErrorForResourceBusy) {
ImmutableList<DrmInitData.SchemeData> secondSchemeDatas =
ImmutableList.of(DRM_SCHEME_DATAS.get(0).copyWithData(TestUtil.createByteArray(4, 5, 6)));
FakeExoMediaDrm.LicenseServer licenseServer =
@ -267,7 +283,13 @@ public class DefaultDrmSessionManagerTest {
DrmSessionManager drmSessionManager =
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm(/* maxConcurrentSessions= */ 1))
DRM_SCHEME_UUID,
uuid ->
new FakeExoMediaDrm.Builder()
.setMaxConcurrentSessions(1)
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForResourceBusy)
.build())
.setSessionKeepaliveMs(10_000)
.setMultiSession(true)
.build(/* mediaDrmCallback= */ licenseServer);
@ -298,6 +320,23 @@ public class DefaultDrmSessionManagerTest {
@Test(timeout = 10_000)
public void maxConcurrentSessionsExceeded_allPreacquiredAndKeepaliveSessionsEagerlyReleased()
throws Exception {
maxConcurrentSessionsExceededAllPreacquiredAndKeepaliveSessionsEagerlyReleased(
/* throwNoSuchMethodErrorForResourceBusy= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test(timeout = 10_000)
public void
maxConcurrentSessionsExceeded_allPreacquiredAndKeepaliveSessionsEagerlyReleased_noSuchMethodError()
throws Exception {
maxConcurrentSessionsExceededAllPreacquiredAndKeepaliveSessionsEagerlyReleased(
/* throwNoSuchMethodErrorForResourceBusy= */ true);
}
private static void
maxConcurrentSessionsExceededAllPreacquiredAndKeepaliveSessionsEagerlyReleased(
boolean throwNoSuchMethodErrorForResourceBusy) {
ImmutableList<DrmInitData.SchemeData> secondSchemeDatas =
ImmutableList.of(DRM_SCHEME_DATAS.get(0).copyWithData(TestUtil.createByteArray(4, 5, 6)));
FakeExoMediaDrm.LicenseServer licenseServer =
@ -308,7 +347,12 @@ public class DefaultDrmSessionManagerTest {
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID,
uuid -> new FakeExoMediaDrm.Builder().setMaxConcurrentSessions(1).build())
uuid ->
new FakeExoMediaDrm.Builder()
.setMaxConcurrentSessions(1)
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForResourceBusy)
.build())
.setSessionKeepaliveMs(10_000)
.setMultiSession(true)
.build(/* mediaDrmCallback= */ licenseServer);
@ -606,6 +650,22 @@ public class DefaultDrmSessionManagerTest {
@Test
public void
deviceNotProvisioned_exceptionThrownFromOpenSession_provisioningDoneAndOpenSessionRetried() {
deviceNotProvisionedExceptionThrownFromOpenSessionProvisioningDoneAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test
public void
deviceNotProvisioned_exceptionThrownFromOpenSession_provisioningDoneAndOpenSessionRetried_noSuchMethodError() {
deviceNotProvisionedExceptionThrownFromOpenSessionProvisioningDoneAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ true);
}
private static void
deviceNotProvisionedExceptionThrownFromOpenSessionProvisioningDoneAndOpenSessionRetried(
boolean throwNoSuchMethodErrorForNotProvisioned) {
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
@ -613,7 +673,12 @@ public class DefaultDrmSessionManagerTest {
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID,
uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(1).build())
uuid ->
new FakeExoMediaDrm.Builder()
.setProvisionsRequired(1)
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForNotProvisioned)
.build())
.build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
drmSessionManager.prepare();
@ -635,6 +700,22 @@ public class DefaultDrmSessionManagerTest {
@Test
public void
deviceNotProvisioned_exceptionThrownFromGetKeyRequest_provisioningDoneAndOpenSessionRetried() {
deviceNotProvisionedExceptionThrownFromGetKeyRequestProvisioningDoneAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test
public void
deviceNotProvisioned_exceptionThrownFromGetKeyRequest_provisioningDoneAndOpenSessionRetried_noSuchMethodError() {
deviceNotProvisionedExceptionThrownFromGetKeyRequestProvisioningDoneAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ true);
}
private static void
deviceNotProvisionedExceptionThrownFromGetKeyRequestProvisioningDoneAndOpenSessionRetried(
boolean throwNoSuchMethodErrorForNotProvisioned) {
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
@ -646,6 +727,8 @@ public class DefaultDrmSessionManagerTest {
new FakeExoMediaDrm.Builder()
.setProvisionsRequired(1)
.throwNotProvisionedExceptionFromGetKeyRequest()
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForNotProvisioned)
.build())
.build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
@ -665,6 +748,21 @@ public class DefaultDrmSessionManagerTest {
@Test
public void deviceNotProvisioned_doubleProvisioningHandledAndOpenSessionRetried() {
deviceNotProvisionedDoubleProvisioningHandledAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test
public void
deviceNotProvisioned_doubleProvisioningHandledAndOpenSessionRetried_noSuchMethodError() {
deviceNotProvisionedDoubleProvisioningHandledAndOpenSessionRetried(
/* throwNoSuchMethodErrorForNotProvisioned= */ true);
}
private static void deviceNotProvisionedDoubleProvisioningHandledAndOpenSessionRetried(
boolean throwNoSuchMethodErrorForNotProvisioned) {
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
@ -672,7 +770,12 @@ public class DefaultDrmSessionManagerTest {
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID,
uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(2).build())
uuid ->
new FakeExoMediaDrm.Builder()
.setProvisionsRequired(2)
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForNotProvisioned)
.build())
.build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
drmSessionManager.prepare();
@ -693,6 +796,20 @@ public class DefaultDrmSessionManagerTest {
@Test
public void keyResponseIndicatesProvisioningRequired_provisioningDone() {
keyResponseIndicatesProvisioningRequiredProvisioningDone(
/* throwNoSuchMethodErrorForNotProvisioned= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test
public void keyResponseIndicatesProvisioningRequired_provisioningDone_noSuchMethodError() {
keyResponseIndicatesProvisioningRequiredProvisioningDone(
/* throwNoSuchMethodErrorForNotProvisioned= */ true);
}
private static void keyResponseIndicatesProvisioningRequiredProvisioningDone(
boolean throwNoSuchMethodErrorForNotProvisioned) {
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.requiringProvisioningThenAllowingSchemeDatas(
DRM_SCHEME_DATAS);
@ -700,7 +817,12 @@ public class DefaultDrmSessionManagerTest {
DefaultDrmSessionManager drmSessionManager =
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(
DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm.Builder().build())
DRM_SCHEME_UUID,
uuid ->
new FakeExoMediaDrm.Builder()
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForNotProvisioned)
.build())
.build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
drmSessionManager.prepare();
@ -719,10 +841,29 @@ public class DefaultDrmSessionManagerTest {
@Test
public void provisioningUndoneWhileManagerIsActive_deviceReprovisioned() {
provisioningUndoneWhileManagerIsActiveDeviceReprovisioned(
/* throwNoSuchMethodErrorForNotProvisioned= */ false);
}
/** Testing workarounds for b/291440132. */
@Config(sdk = 34)
@Test
public void provisioningUndoneWhileManagerIsActive_deviceReprovisioned_noSuchMethodError() {
provisioningUndoneWhileManagerIsActiveDeviceReprovisioned(
/* throwNoSuchMethodErrorForNotProvisioned= */ true);
}
private static void provisioningUndoneWhileManagerIsActiveDeviceReprovisioned(
boolean throwNoSuchMethodErrorForNotProvisioned) {
FakeExoMediaDrm.LicenseServer licenseServer =
FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
FakeExoMediaDrm mediaDrm = new FakeExoMediaDrm.Builder().setProvisionsRequired(2).build();
FakeExoMediaDrm mediaDrm =
new FakeExoMediaDrm.Builder()
.setProvisionsRequired(2)
.throwNoSuchMethodErrorForProvisioningAndResourceBusy(
throwNoSuchMethodErrorForNotProvisioned)
.build();
DefaultDrmSessionManager drmSessionManager =
new DefaultDrmSessionManager.Builder()
.setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, new AppManagedProvider(mediaDrm))

View File

@ -16,6 +16,8 @@
package androidx.media3.test.utils;
import static androidx.media3.common.util.Assertions.checkState;
import android.media.DeniedByServerException;
import android.media.MediaCryptoException;
import android.media.MediaDrmException;
@ -72,6 +74,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
private int provisionsRequired;
private boolean throwNotProvisionedExceptionFromGetKeyRequest;
private int maxConcurrentSessions;
private boolean throwNoSuchMethodErrorForProvisioningAndResourceBusy;
/** Constructs an instance. */
public Builder() {
@ -119,6 +122,26 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
return this;
}
/**
* Configures the {@link FakeExoMediaDrm} to throw {@link NoSuchMethodError} instead of {@link
* NotProvisionedException} or {@link ResourceBusyException}.
*
* <p>This simulates a framework bug (b/291440132) introduced in API 34 and resolved by
* http://r.android.com/2770659, allowing us to test workarounds for the bug.
*
* <p>The default is {@code false}.
*/
@CanIgnoreReturnValue
public Builder throwNoSuchMethodErrorForProvisioningAndResourceBusy(
boolean throwNoSuchMethodErrorForProvisioningAndResourceBusy) {
checkState(
!throwNoSuchMethodErrorForProvisioningAndResourceBusy || Util.SDK_INT == 34,
"The framework bug recreated by this method only exists on API 34.");
this.throwNoSuchMethodErrorForProvisioningAndResourceBusy =
throwNoSuchMethodErrorForProvisioningAndResourceBusy;
return this;
}
/**
* Sets the maximum number of concurrent sessions the {@link FakeExoMediaDrm} will support.
*
@ -143,6 +166,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
enforceValidKeyResponses,
provisionsRequired,
throwNotProvisionedExceptionFromGetKeyRequest,
throwNoSuchMethodErrorForProvisioningAndResourceBusy,
maxConcurrentSessions);
}
}
@ -170,6 +194,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
private final int provisionsRequired;
private final int maxConcurrentSessions;
private final boolean throwNotProvisionedExceptionFromGetKeyRequest;
private final boolean throwNoSuchMethodErrorForProvisioningAndResourceBusy;
private final Map<String, byte[]> byteProperties;
private final Map<String, String> stringProperties;
private final Set<List<Byte>> openSessionIds;
@ -184,12 +209,9 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
@SuppressWarnings("deprecation") // Using deprecated constructor to reduce duplication.
public FakeExoMediaDrm() {
this(
/* enforceValidKeyResponses= */ true,
/* provisionsRequired= */ 0,
/* throwNotProvisionedExceptionFromGetKeyRequest= */ false,
/* maxConcurrentSessions= */ Integer.MAX_VALUE);
this(/* maxConcurrentSessions= */ Integer.MAX_VALUE);
}
/**
@ -201,6 +223,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
/* enforceValidKeyResponses= */ true,
/* provisionsRequired= */ 0,
/* throwNotProvisionedExceptionFromGetKeyRequest= */ false,
/* throwNoSuchMethodErrorForProvisioningAndResourceBusy= */ false,
maxConcurrentSessions);
}
@ -208,12 +231,15 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
boolean enforceValidKeyResponses,
int provisionsRequired,
boolean throwNotProvisionedExceptionFromGetKeyRequest,
boolean throwNoSuchMethodErrorForProvisioningAndResourceBusy,
int maxConcurrentSessions) {
this.enforceValidKeyResponses = enforceValidKeyResponses;
this.provisionsRequired = provisionsRequired;
this.maxConcurrentSessions = maxConcurrentSessions;
this.throwNotProvisionedExceptionFromGetKeyRequest =
throwNotProvisionedExceptionFromGetKeyRequest;
this.throwNoSuchMethodErrorForProvisioningAndResourceBusy =
throwNoSuchMethodErrorForProvisioningAndResourceBusy;
byteProperties = new HashMap<>();
stringProperties = new HashMap<>();
openSessionIds = new HashSet<>();
@ -244,10 +270,16 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
public byte[] openSession() throws MediaDrmException {
Assertions.checkState(referenceCount > 0);
if (!throwNotProvisionedExceptionFromGetKeyRequest && provisionsReceived < provisionsRequired) {
throw new NotProvisionedException("Not provisioned.");
throwNotProvisionedException();
}
if (openSessionIds.size() >= maxConcurrentSessions) {
throw new ResourceBusyException("Too many sessions open. max=" + maxConcurrentSessions);
if (throwNoSuchMethodErrorForProvisioningAndResourceBusy) {
throw new NoSuchMethodError(
"no non-static method"
+ " \"Landroid/media/ResourceBusyException;.<init>(Ljava/lang/String;III)V\"");
} else {
throw new ResourceBusyException("Too many sessions open. max=" + maxConcurrentSessions);
}
}
byte[] sessionId =
TestUtil.buildTestData(/* length= */ 10, sessionIdGenerator.incrementAndGet());
@ -280,7 +312,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
}
Assertions.checkArgument(keyType == KEY_TYPE_STREAMING, "Unrecognised keyType: " + keyType);
if (throwNotProvisionedExceptionFromGetKeyRequest && provisionsReceived < provisionsRequired) {
throw new NotProvisionedException("Not provisioned.");
throwNotProvisionedException();
}
Assertions.checkState(openSessionIds.contains(toByteList(scope)));
Assertions.checkNotNull(schemeDatas);
@ -306,7 +338,7 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
throw new DeniedByServerException("Key request denied");
}
if (responseAsList.equals(PROVISIONING_REQUIRED_RESPONSE)) {
throw new NotProvisionedException("Provisioning required");
throwNotProvisionedException();
}
if (enforceValidKeyResponses && !responseAsList.equals(VALID_KEY_RESPONSE)) {
throw new IllegalArgumentException(
@ -451,6 +483,16 @@ public final class FakeExoMediaDrm implements ExoMediaDrm {
provisionsReceived = 0;
}
private void throwNotProvisionedException() throws NotProvisionedException {
if (throwNoSuchMethodErrorForProvisioningAndResourceBusy) {
throw new NoSuchMethodError(
"no non-static method"
+ " \"Landroid/media/NotProvisionedException;.<init>(Ljava/lang/String;III)V\"");
} else {
throw new NotProvisionedException("Not provisioned.");
}
}
private static ImmutableList<Byte> toByteList(byte[] byteArray) {
return ImmutableList.copyOf(Bytes.asList(byteArray));
}