DataSource.open() throws if already opened.

Update DataSource implementations to throw an error if open() is called
when the DataSource is already open.

PiperOrigin-RevId: 348609860
This commit is contained in:
christosts 2020-12-22 11:47:39 +00:00 committed by Oliver Woodman
parent 0226543090
commit dd7b379dc0
21 changed files with 90 additions and 18 deletions

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.ext.media2; package com.google.android.exoplayer2.ext.media2;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.os.Looper; import android.os.Looper;
@ -143,6 +145,7 @@ import org.junit.rules.ExternalResource;
private final DataSource wrappedDataSource; private final DataSource wrappedDataSource;
private final DataSourceInstrumentation instrumentation; private final DataSourceInstrumentation instrumentation;
private boolean opened;
public InstrumentedDataSource( public InstrumentedDataSource(
DataSource wrappedDataSource, DataSourceInstrumentation instrumentation) { DataSource wrappedDataSource, DataSourceInstrumentation instrumentation) {
@ -157,8 +160,11 @@ import org.junit.rules.ExternalResource;
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
instrumentation.onPreOpen(dataSpec); instrumentation.onPreOpen(dataSpec);
return wrappedDataSource.open(dataSpec); long length = wrappedDataSource.open(dataSpec);
opened = true;
return length;
} }
@Nullable @Nullable
@ -180,6 +186,7 @@ import org.junit.rules.ExternalResource;
@Override @Override
public void close() throws IOException { public void close() throws IOException {
wrappedDataSource.close(); wrappedDataSource.close();
opened = false;
} }
} }
} }

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.ext.okhttp; package com.google.android.exoplayer2.ext.okhttp;
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -277,6 +278,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws HttpDataSourceException { public long open(DataSpec dataSpec) throws HttpDataSourceException {
checkState(!opened);
this.dataSpec = dataSpec; this.dataSpec = dataSpec;
this.bytesRead = 0; this.bytesRead = 0;
this.bytesSkipped = 0; this.bytesSkipped = 0;

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.ext.rtmp; package com.google.android.exoplayer2.ext.rtmp;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri; import android.net.Uri;
@ -37,6 +38,7 @@ public final class RtmpDataSource extends BaseDataSource {
@Nullable private RtmpClient rtmpClient; @Nullable private RtmpClient rtmpClient;
@Nullable private Uri uri; @Nullable private Uri uri;
private boolean opened;
public RtmpDataSource() { public RtmpDataSource() {
super(/* isNetwork= */ true); super(/* isNetwork= */ true);
@ -44,12 +46,14 @@ public final class RtmpDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws RtmpIOException { public long open(DataSpec dataSpec) throws RtmpIOException {
checkState(!opened);
transferInitializing(dataSpec); transferInitializing(dataSpec);
rtmpClient = new RtmpClient(); rtmpClient = new RtmpClient();
rtmpClient.open(dataSpec.uri.toString(), false); rtmpClient.open(dataSpec.uri.toString(), false);
this.uri = dataSpec.uri; this.uri = dataSpec.uri;
transferStarted(dataSpec); transferStarted(dataSpec);
opened = true;
return C.LENGTH_UNSET; return C.LENGTH_UNSET;
} }
@ -73,6 +77,7 @@ public final class RtmpDataSource extends BaseDataSource {
rtmpClient.close(); rtmpClient.close();
rtmpClient = null; rtmpClient = null;
} }
opened = false;
} }
@Override @Override

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -57,6 +58,7 @@ public final class AssetDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws AssetDataSourceException { public long open(DataSpec dataSpec) throws AssetDataSourceException {
checkState(!opened);
try { try {
uri = dataSpec.uri; uri = dataSpec.uri;
String path = Assertions.checkNotNull(uri.getPath()); String path = Assertions.checkNotNull(uri.getPath());

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.net.Uri; import android.net.Uri;
@ -45,6 +46,7 @@ public final class ByteArrayDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
uri = dataSpec.uri; uri = dataSpec.uri;
transferInitializing(dataSpec); transferInitializing(dataSpec);
readPosition = (int) dataSpec.position; readPosition = (int) dataSpec.position;

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -62,6 +63,8 @@ public final class ContentDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws ContentDataSourceException { public long open(DataSpec dataSpec) throws ContentDataSourceException {
checkState(!opened);
try { try {
Uri uri = dataSpec.uri; Uri uri = dataSpec.uri;
this.uri = uri; this.uri = uri;

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -44,6 +45,7 @@ public final class DataSchemeDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(this.dataSpec == null);
transferInitializing(dataSpec); transferInitializing(dataSpec);
this.dataSpec = dataSpec; this.dataSpec = dataSpec;
readPosition = (int) dataSpec.position; readPosition = (int) dataSpec.position;

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -342,6 +343,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
*/ */
@Override @Override
public long open(DataSpec dataSpec) throws HttpDataSourceException { public long open(DataSpec dataSpec) throws HttpDataSourceException {
checkState(!opened);
this.dataSpec = dataSpec; this.dataSpec = dataSpec;
this.bytesRead = 0; this.bytesRead = 0;
this.bytesSkipped = 0; this.bytesSkipped = 0;

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -80,6 +81,7 @@ public final class FileDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws FileDataSourceException { public long open(DataSpec dataSpec) throws FileDataSourceException {
checkState(!opened);
try { try {
Uri uri = dataSpec.uri; Uri uri = dataSpec.uri;
this.uri = uri; this.uri = uri;

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -40,6 +42,7 @@ public final class PriorityDataSource implements DataSource {
private final DataSource upstream; private final DataSource upstream;
private final PriorityTaskManager priorityTaskManager; private final PriorityTaskManager priorityTaskManager;
private final int priority; private final int priority;
private boolean opened;
/** /**
* @param upstream The upstream {@link DataSource}. * @param upstream The upstream {@link DataSource}.
@ -61,8 +64,11 @@ public final class PriorityDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
priorityTaskManager.proceedOrThrow(priority); priorityTaskManager.proceedOrThrow(priority);
return upstream.open(dataSpec); long length = upstream.open(dataSpec);
opened = true;
return length;
} }
@Override @Override
@ -85,6 +91,7 @@ public final class PriorityDataSource implements DataSource {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
upstream.close(); upstream.close();
opened = false;
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -98,6 +99,7 @@ public final class RawResourceDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws RawResourceDataSourceException { public long open(DataSpec dataSpec) throws RawResourceDataSourceException {
checkState(!opened);
Uri uri = dataSpec.uri; Uri uri = dataSpec.uri;
this.uri = uri; this.uri = uri;

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -103,6 +104,7 @@ public final class ResolvingDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!upstreamOpened);
DataSpec resolvedDataSpec = resolver.resolveDataSpec(dataSpec); DataSpec resolvedDataSpec = resolver.resolveDataSpec(dataSpec);
upstreamOpened = true; upstreamOpened = true;
return upstreamDataSource.open(resolvedDataSpec); return upstreamDataSource.open(resolvedDataSpec);

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
@ -35,6 +37,7 @@ public final class StatsDataSource implements DataSource {
private long bytesRead; private long bytesRead;
private Uri lastOpenedUri; private Uri lastOpenedUri;
private Map<String, List<String>> lastResponseHeaders; private Map<String, List<String>> lastResponseHeaders;
private boolean opened;
/** /**
* Creates the stats data source. * Creates the stats data source.
@ -78,12 +81,14 @@ public final class StatsDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
// Reassign defaults in case dataSource.open throws an exception. // Reassign defaults in case dataSource.open throws an exception.
lastOpenedUri = dataSpec.uri; lastOpenedUri = dataSpec.uri;
lastResponseHeaders = Collections.emptyMap(); lastResponseHeaders = Collections.emptyMap();
long availableBytes = dataSource.open(dataSpec); long availableBytes = dataSource.open(dataSpec);
lastOpenedUri = Assertions.checkNotNull(getUri()); lastOpenedUri = Assertions.checkNotNull(getUri());
lastResponseHeaders = getResponseHeaders(); lastResponseHeaders = getResponseHeaders();
opened = true;
return availableBytes; return availableBytes;
} }
@ -110,5 +115,6 @@ public final class StatsDataSource implements DataSource {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
dataSource.close(); dataSource.close();
opened = false;
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.net.Uri; import android.net.Uri;
@ -89,6 +90,8 @@ public final class UdpDataSource extends BaseDataSource {
@Override @Override
public long open(DataSpec dataSpec) throws UdpDataSourceException { public long open(DataSpec dataSpec) throws UdpDataSourceException {
checkState(!opened);
uri = dataSpec.uri; uri = dataSpec.uri;
String host = uri.getHost(); String host = uri.getHost();
int port = uri.getPort(); int port = uri.getPort();

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.cache; package com.google.android.exoplayer2.upstream.cache;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -33,7 +34,6 @@ import com.google.android.exoplayer2.upstream.PriorityDataSource;
import com.google.android.exoplayer2.upstream.TeeDataSource; import com.google.android.exoplayer2.upstream.TeeDataSource;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.Cache.CacheException; import com.google.android.exoplayer2.upstream.cache.Cache.CacheException;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.PriorityTaskManager; import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException; import java.io.IOException;
import java.io.InterruptedIOException; import java.io.InterruptedIOException;
@ -397,6 +397,7 @@ public final class CacheDataSource implements DataSource {
private boolean currentRequestIgnoresCache; private boolean currentRequestIgnoresCache;
private long totalCachedBytesRead; private long totalCachedBytesRead;
private long checkCachePosition; private long checkCachePosition;
private boolean opened;
/** /**
* Constructs an instance with default {@link DataSource} and {@link DataSink} instances for * Constructs an instance with default {@link DataSource} and {@link DataSink} instances for
@ -552,6 +553,7 @@ public final class CacheDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
try { try {
String key = cacheKeyFactory.buildCacheKey(dataSpec); String key = cacheKeyFactory.buildCacheKey(dataSpec);
DataSpec requestDataSpec = dataSpec.buildUpon().setKey(key).build(); DataSpec requestDataSpec = dataSpec.buildUpon().setKey(key).build();
@ -577,6 +579,7 @@ public final class CacheDataSource implements DataSource {
} }
} }
openNextSource(requestDataSpec, false); openNextSource(requestDataSpec, false);
opened = true;
return bytesRemaining; return bytesRemaining;
} catch (Throwable e) { } catch (Throwable e) {
handleBeforeThrow(e); handleBeforeThrow(e);
@ -649,6 +652,7 @@ public final class CacheDataSource implements DataSource {
notifyBytesRead(); notifyBytesRead();
try { try {
closeCurrentSource(); closeCurrentSource();
opened = false;
} catch (Throwable e) { } catch (Throwable e) {
handleBeforeThrow(e); handleBeforeThrow(e);
throw e; throw e;
@ -739,7 +743,7 @@ public final class CacheDataSource implements DataSource {
? readPosition + MIN_READ_BEFORE_CHECKING_CACHE ? readPosition + MIN_READ_BEFORE_CHECKING_CACHE
: Long.MAX_VALUE; : Long.MAX_VALUE;
if (checkCache) { if (checkCache) {
Assertions.checkState(isBypassingCache()); checkState(isBypassingCache());
if (nextDataSource == upstreamDataSource) { if (nextDataSource == upstreamDataSource) {
// Continue reading from upstream. // Continue reading from upstream.
return; return;

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.crypto; package com.google.android.exoplayer2.upstream.crypto;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri; import android.net.Uri;
@ -36,6 +37,7 @@ public final class AesCipherDataSource implements DataSource {
private final DataSource upstream; private final DataSource upstream;
private final byte[] secretKey; private final byte[] secretKey;
private boolean opened;
@Nullable private AesFlushingCipher cipher; @Nullable private AesFlushingCipher cipher;
@ -52,11 +54,13 @@ public final class AesCipherDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
long dataLength = upstream.open(dataSpec); long dataLength = upstream.open(dataSpec);
long nonce = CryptoUtil.getFNV64Hash(dataSpec.key); long nonce = CryptoUtil.getFNV64Hash(dataSpec.key);
cipher = cipher =
new AesFlushingCipher( new AesFlushingCipher(
Cipher.DECRYPT_MODE, secretKey, nonce, dataSpec.uriPositionOffset + dataSpec.position); Cipher.DECRYPT_MODE, secretKey, nonce, dataSpec.uriPositionOffset + dataSpec.position);
opened = true;
return dataLength; return dataLength;
} }
@ -88,5 +92,6 @@ public final class AesCipherDataSource implements DataSource {
public void close() throws IOException { public void close() throws IOException {
cipher = null; cipher = null;
upstream.close(); upstream.close();
opened = false;
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
@ -89,14 +90,18 @@ public class BaseDataSourceTest {
private static final class TestSource extends BaseDataSource { private static final class TestSource extends BaseDataSource {
private boolean opened;
public TestSource(boolean isNetwork) { public TestSource(boolean isNetwork) {
super(isNetwork); super(isNetwork);
} }
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
transferInitializing(dataSpec); transferInitializing(dataSpec);
transferStarted(dataSpec); transferStarted(dataSpec);
opened = true;
return C.LENGTH_UNSET; return C.LENGTH_UNSET;
} }
@ -115,6 +120,7 @@ public class BaseDataSourceTest {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
transferEnded(); transferEnded();
opened = false;
} }
} }

View file

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.C.RESULT_END_OF_INPUT; import static com.google.android.exoplayer2.C.RESULT_END_OF_INPUT;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
@ -130,19 +131,20 @@ public final class DataSchemeDataSourceTest {
} }
@Test @Test
public void malformedData() { public void malformedData_throwsIOException() {
try { assertThrows(
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,,This%20is%20Content")); IOException.class,
fail(); () ->
} catch (IOException e) { schemeDataDataSource.open(
// Expected. buildDataSpec("data:text/plain;base64,,This%20is%20Content")));
} }
try {
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,IncorrectPadding==")); @Test
fail(); public void malformedData_incorrectPadding_throwsIOException() {
} catch (IOException e) { assertThrows(
// Expected. IOException.class,
} () ->
schemeDataDataSource.open(buildDataSpec("data:text/plain;base64,IncorrectPadding==")));
} }
@Test @Test

View file

@ -284,6 +284,7 @@ public final class CacheDataSourceTest {
cacheDataSource.open( cacheDataSource.open(
buildDataSpec(TEST_DATA.length - 2, C.LENGTH_UNSET, defaultCacheKey))) buildDataSpec(TEST_DATA.length - 2, C.LENGTH_UNSET, defaultCacheKey)))
.isEqualTo(2); .isEqualTo(2);
cacheDataSource.close();
// An unbounded request with offset for not cached content. // An unbounded request with offset for not cached content.
dataSpec = dataSpec =

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
@ -50,6 +52,7 @@ import javax.crypto.spec.SecretKeySpec;
private final DataSource upstream; private final DataSource upstream;
private final byte[] encryptionKey; private final byte[] encryptionKey;
private final byte[] encryptionIv; private final byte[] encryptionIv;
private boolean opened;
@Nullable private CipherInputStream cipherInputStream; @Nullable private CipherInputStream cipherInputStream;
@ -72,6 +75,7 @@ import javax.crypto.spec.SecretKeySpec;
@Override @Override
public final long open(DataSpec dataSpec) throws IOException { public final long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
Cipher cipher; Cipher cipher;
try { try {
cipher = getCipherInstance(); cipher = getCipherInstance();
@ -91,7 +95,7 @@ import javax.crypto.spec.SecretKeySpec;
DataSourceInputStream inputStream = new DataSourceInputStream(upstream, dataSpec); DataSourceInputStream inputStream = new DataSourceInputStream(upstream, dataSpec);
cipherInputStream = new CipherInputStream(inputStream, cipher); cipherInputStream = new CipherInputStream(inputStream, cipher);
inputStream.open(); inputStream.open();
opened = true;
return C.LENGTH_UNSET; return C.LENGTH_UNSET;
} }
@ -121,6 +125,7 @@ import javax.crypto.spec.SecretKeySpec;
if (cipherInputStream != null) { if (cipherInputStream != null) {
cipherInputStream = null; cipherInputStream = null;
upstream.close(); upstream.close();
opened = false;
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
@ -104,6 +105,7 @@ public class Aes128DataSourceTest {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
checkState(!opened);
opened = true; opened = true;
return C.LENGTH_UNSET; return C.LENGTH_UNSET;
} }