diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index f8abfbe894..d57ccccc81 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -25,13 +25,9 @@ import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.SystemClock; -import android.system.ErrnoException; -import android.system.OsConstants; import android.util.Pair; import androidx.annotation.CheckResult; -import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.DefaultMediaClock.PlaybackParametersListener; import com.google.android.exoplayer2.PlaybackException.ErrorCode; import com.google.android.exoplayer2.Player.DiscontinuityReason; @@ -63,7 +59,6 @@ import com.google.android.exoplayer2.util.TraceUtil; import com.google.android.exoplayer2.util.Util; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; -import java.io.FileNotFoundException; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; @@ -586,21 +581,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } catch (DrmSession.DrmSessionException e) { handleIoException(e, e.errorCode); } catch (FileDataSource.FileDataSourceException e) { - @Nullable Throwable cause = e.getCause(); - @ErrorCode int errorCode; - if (cause instanceof FileNotFoundException) { - if (Util.SDK_INT >= 21 - && PlatformOperationsWrapperV21.isPermissionError(cause.getCause())) { - errorCode = PlaybackException.ERROR_CODE_IO_NO_PERMISSION; - } else { - errorCode = PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND; - } - } else if (cause instanceof SecurityException) { - errorCode = PlaybackException.ERROR_CODE_IO_NO_PERMISSION; - } else { - errorCode = PlaybackException.ERROR_CODE_IO_UNSPECIFIED; - } - handleIoException(e, errorCode); + handleIoException(e, e.reason); } catch (ParserException e) { @ErrorCode int errorCode; if (e.dataType == C.DATA_TYPE_MEDIA) { @@ -3065,13 +3046,4 @@ import java.util.concurrent.atomic.AtomicBoolean; this.shuffleOrder = shuffleOrder; } } - - @RequiresApi(21) - private static final class PlatformOperationsWrapperV21 { - - @DoNotInline - public static boolean isPermissionError(@Nullable Throwable e) { - return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES; - } - } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java index 0d78c100c5..8640e5f6ac 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSource.java @@ -19,11 +19,16 @@ import static com.google.android.exoplayer2.util.Util.castNonNull; import static java.lang.Math.min; import android.net.Uri; +import android.system.ErrnoException; +import android.system.OsConstants; import android.text.TextUtils; +import androidx.annotation.DoNotInline; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; @@ -32,14 +37,29 @@ import java.io.RandomAccessFile; public final class FileDataSource extends BaseDataSource { /** Thrown when a {@link FileDataSource} encounters an error reading a file. */ - public static class FileDataSourceException extends IOException { + public static class FileDataSourceException extends DataSourceException { + /** @deprecated Use {@link #FileDataSourceException(Throwable, int)} */ + @Deprecated public FileDataSourceException(Exception cause) { - super(cause); + super(cause, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); } + /** @deprecated Use {@link #FileDataSourceException(String, Throwable, int)} */ + @Deprecated public FileDataSourceException(String message, IOException cause) { - super(message, cause); + super(message, cause, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); + } + + /** Creates a {@code FileDataSourceException}. */ + public FileDataSourceException(Throwable cause, @PlaybackException.ErrorCode int errorCode) { + super(cause, errorCode); + } + + /** Creates a {@code FileDataSourceException}. */ + public FileDataSourceException( + String message, Throwable cause, @PlaybackException.ErrorCode int errorCode) { + super(message, cause, errorCode); } } @@ -95,8 +115,10 @@ public final class FileDataSource extends BaseDataSource { } } catch (FileDataSourceException e) { throw e; - } catch (Exception e) { - throw new FileDataSourceException(e); + } catch (DataSourceException e) { + throw new FileDataSourceException(e, e.reason); + } catch (IOException | RuntimeException e) { + throw new FileDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); } opened = true; @@ -116,7 +138,7 @@ public final class FileDataSource extends BaseDataSource { try { bytesRead = castNonNull(file).read(buffer, offset, (int) min(bytesRemaining, readLength)); } catch (IOException e) { - throw new FileDataSourceException(e); + throw new FileDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); } if (bytesRead > 0) { @@ -142,7 +164,7 @@ public final class FileDataSource extends BaseDataSource { file.close(); } } catch (IOException e) { - throw new FileDataSourceException(e); + throw new FileDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); } finally { file = null; if (opened) { @@ -163,9 +185,29 @@ public final class FileDataSource extends BaseDataSource { + " on a string containing '?' or '#'? Use Uri.fromFile(new File(path)) to" + " avoid this. path=%s,query=%s,fragment=%s", uri.getPath(), uri.getQuery(), uri.getFragment()), - e); + e, + PlaybackException.ERROR_CODE_IO_UNSPECIFIED); } - throw new FileDataSourceException(e); + + // TODO(internal b/193503588): Add tests to ensure the correct error codes are assigned under + // different SDK versions. + throw new FileDataSourceException( + e, + Util.SDK_INT >= 21 && PlatformOperationsWrapperV21.isPermissionError(e.getCause()) + ? PlaybackException.ERROR_CODE_IO_NO_PERMISSION + : PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND); + } catch (SecurityException e) { + throw new FileDataSourceException(e, PlaybackException.ERROR_CODE_IO_NO_PERMISSION); + } catch (RuntimeException e) { + throw new FileDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); + } + } + + @RequiresApi(21) + private static final class PlatformOperationsWrapperV21 { + @DoNotInline + private static boolean isPermissionError(@Nullable Throwable e) { + return e instanceof ErrnoException && ((ErrnoException) e).errno == OsConstants.EACCES; } } }