Commit 87865a5c by olly Committed by Oliver Woodman

DefaultDownloadIndex: Clear failure reason when removing download

The Download constructor considers it invalid to have a failure
reason if the download isn't in the failed state. Unfortunately,
calling DefaultDownloadIndex.removeAllDownloads when there's a
failed download will change the state without clearing the reason.
If the downloads are then read back from the DefaultDownloadIndex
we end up violating the Download constructor assertion.

This change clears the failed reason for any existing rows in the
invalid state, and also fixes the root cause that allows invalid
rows to enter the table in the first place.

Issue: #6785
PiperOrigin-RevId: 286576242
parent 406acfc3
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
`SsaStyle$SsaAlignment` `SsaStyle$SsaAlignment`
([#6771](https://github.com/google/ExoPlayer/issues/6771)). ([#6771](https://github.com/google/ExoPlayer/issues/6771)).
* Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`. * Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`.
* Fix issue with `DefaultDownloadIndex` that could result in an
`IllegalStateException` being thrown from
`DefaultDownloadIndex.getDownloadForCurrentRow`
([#6785](https://github.com/google/ExoPlayer/issues/6785)).
* Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and * Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and
`SimpleDecoderAudioRenderer.getMediaClock` `SimpleDecoderAudioRenderer.getMediaClock`
([#6792](https://github.com/google/ExoPlayer/issues/6792)). ([#6792](https://github.com/google/ExoPlayer/issues/6792)).
......
...@@ -26,6 +26,8 @@ import androidx.annotation.VisibleForTesting; ...@@ -26,6 +26,8 @@ import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.database.DatabaseIOException; import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.VersionTable; import com.google.android.exoplayer2.database.VersionTable;
import com.google.android.exoplayer2.offline.Download.FailureReason;
import com.google.android.exoplayer2.offline.Download.State;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -239,6 +241,9 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -239,6 +241,9 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
try { try {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(COLUMN_STATE, Download.STATE_REMOVING); values.put(COLUMN_STATE, Download.STATE_REMOVING);
// Only downloads in STATE_FAILED are allowed a failure reason, so we need to clear it here in
// case we're moving downloads from STATE_FAILED to STATE_REMOVING.
values.put(COLUMN_FAILURE_REASON, Download.FAILURE_REASON_NONE);
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null); writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null);
} catch (SQLException e) { } catch (SQLException e) {
...@@ -351,14 +356,22 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { ...@@ -351,14 +356,22 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
DownloadProgress downloadProgress = new DownloadProgress(); DownloadProgress downloadProgress = new DownloadProgress();
downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_DOWNLOADED); downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_DOWNLOADED);
downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_PERCENT_DOWNLOADED); downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_PERCENT_DOWNLOADED);
@State int state = cursor.getInt(COLUMN_INDEX_STATE);
// It's possible the database contains failure reasons for non-failed downloads, which is
// invalid. Clear them here. See https://github.com/google/ExoPlayer/issues/6785.
@FailureReason
int failureReason =
state == Download.STATE_FAILED
? cursor.getInt(COLUMN_INDEX_FAILURE_REASON)
: Download.FAILURE_REASON_NONE;
return new Download( return new Download(
request, request,
/* state= */ cursor.getInt(COLUMN_INDEX_STATE), state,
/* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS), /* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS),
/* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS), /* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
/* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH), /* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH),
/* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON), /* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON),
/* failureReason= */ cursor.getInt(COLUMN_INDEX_FAILURE_REASON), failureReason,
downloadProgress); downloadProgress);
} }
......
...@@ -130,9 +130,9 @@ public final class Download { ...@@ -130,9 +130,9 @@ public final class Download {
@FailureReason int failureReason, @FailureReason int failureReason,
DownloadProgress progress) { DownloadProgress progress) {
Assertions.checkNotNull(progress); Assertions.checkNotNull(progress);
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED)); Assertions.checkArgument((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
if (stopReason != 0) { if (stopReason != 0) {
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED); Assertions.checkArgument(state != STATE_DOWNLOADING && state != STATE_QUEUED);
} }
this.request = request; this.request = request;
this.state = state; this.state = state;
......
...@@ -249,6 +249,23 @@ public class DefaultDownloadIndexTest { ...@@ -249,6 +249,23 @@ public class DefaultDownloadIndexTest {
} }
@Test @Test
public void setStatesToRemoving_setsStateAndClearsFailureReason() throws Exception {
String id = "id";
DownloadBuilder downloadBuilder =
new DownloadBuilder(id)
.setState(Download.STATE_FAILED)
.setFailureReason(Download.FAILURE_REASON_UNKNOWN);
Download download = downloadBuilder.build();
downloadIndex.putDownload(download);
downloadIndex.setStatesToRemoving();
download = downloadIndex.getDownload(id);
assertThat(download.state).isEqualTo(Download.STATE_REMOVING);
assertThat(download.failureReason).isEqualTo(Download.FAILURE_REASON_NONE);
}
@Test
public void setSingleDownloadStopReason_setReasonToNone() throws Exception { public void setSingleDownloadStopReason_setReasonToNone() throws Exception {
String id = "id"; String id = "id";
DownloadBuilder downloadBuilder = DownloadBuilder downloadBuilder =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment