Commit 17723c08 by aquilescanta Committed by Christos Tsilopoulos

Simplify network-related error codes

This change removes ERROR_CODE_IO_NETWORK_UNAVAILABLE,
ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED, and ERROR_CODE_IO_DNS_FAILED
in favor of keeping only ERROR_CODE_IO_NETWORK_CONNECTION_FAILED.

PiperOrigin-RevId: 388715972
parent f23ab8e2
...@@ -669,12 +669,11 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -669,12 +669,11 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
if (message != null && Ascii.toLowerCase(message).contains("err_cleartext_not_permitted")) { if (message != null && Ascii.toLowerCase(message).contains("err_cleartext_not_permitted")) {
throw new CleartextNotPermittedException(connectionOpenException, dataSpec); throw new CleartextNotPermittedException(connectionOpenException, dataSpec);
} }
@PlaybackException.ErrorCode
int errorCode =
getErrorCodeForException(
connectionOpenException, /* occurredWhileOpeningConnection*/ true);
throw new OpenException( throw new OpenException(
connectionOpenException, dataSpec, errorCode, getStatus(urlRequest)); connectionOpenException,
dataSpec,
PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,
getStatus(urlRequest));
} else if (!connectionOpened) { } else if (!connectionOpened) {
// The timeout was reached before the connection was opened. // The timeout was reached before the connection was opened.
throw new OpenException( throw new OpenException(
...@@ -685,10 +684,13 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -685,10 +684,13 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
// An interruption means the operation is being cancelled, in which case this exception should
// not cause the player to fail. If it does, it likely means that the owner of the operation
// is failing to swallow the interruption, which makes us enter an invalid state.
throw new OpenException( throw new OpenException(
new InterruptedIOException(), new InterruptedIOException(),
dataSpec, dataSpec,
PlaybackException.ERROR_CODE_IO_UNSPECIFIED, PlaybackException.ERROR_CODE_FAILED_RUNTIME_CHECK,
Status.INVALID); Status.INVALID);
} }
...@@ -1029,7 +1031,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -1029,7 +1031,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
throw new OpenException( throw new OpenException(
e, e,
dataSpec, dataSpec,
getErrorCodeForException(e, /* occurredWhileOpeningConnection= */ false), e instanceof SocketTimeoutException
? PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT
: PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,
Status.READING_RESPONSE); Status.READING_RESPONSE);
} }
} }
...@@ -1099,11 +1103,8 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -1099,11 +1103,8 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
if (exception instanceof HttpDataSourceException) { if (exception instanceof HttpDataSourceException) {
throw (HttpDataSourceException) exception; throw (HttpDataSourceException) exception;
} else { } else {
throw new HttpDataSourceException( throw HttpDataSourceException.createForIOException(
exception, exception, dataSpec, HttpDataSourceException.TYPE_READ);
dataSpec,
getErrorCodeForException(exception, /* occurredWhileOpeningConnection= */ false),
HttpDataSourceException.TYPE_READ);
} }
} }
} }
...@@ -1116,27 +1117,6 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { ...@@ -1116,27 +1117,6 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
return readBuffer; return readBuffer;
} }
@PlaybackException.ErrorCode
private static int getErrorCodeForException(
IOException exception, boolean occurredWhileOpeningConnection) {
if (exception instanceof UnknownHostException) {
return PlaybackException.ERROR_CODE_IO_DNS_FAILED;
}
@Nullable String message = exception.getMessage();
if (message != null) {
if (message.contains("net::ERR_INTERNET_DISCONNECTED")) {
return PlaybackException.ERROR_CODE_IO_NETWORK_UNAVAILABLE;
} else if (message.contains("net::ERR_CONTENT_LENGTH_MISMATCH")
|| message.contains("net::ERR_SOCKET_NOT_CONNECTED")) {
return PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED;
}
}
if (occurredWhileOpeningConnection) {
return PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED;
}
return PlaybackException.ERROR_CODE_IO_UNSPECIFIED;
}
private static boolean isCompressed(UrlResponseInfo info) { private static boolean isCompressed(UrlResponseInfo info) {
for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) { for (Map.Entry<String, String> entry : info.getAllHeadersAsList()) {
if (entry.getKey().equalsIgnoreCase("Content-Encoding")) { if (entry.getKey().equalsIgnoreCase("Content-Encoding")) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import android.net.ConnectivityManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
...@@ -48,13 +49,10 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -48,13 +49,10 @@ public class PlaybackException extends Exception implements Bundleable {
ERROR_CODE_TIMEOUT, ERROR_CODE_TIMEOUT,
ERROR_CODE_FAILED_RUNTIME_CHECK, ERROR_CODE_FAILED_RUNTIME_CHECK,
ERROR_CODE_IO_UNSPECIFIED, ERROR_CODE_IO_UNSPECIFIED,
ERROR_CODE_IO_NETWORK_UNAVAILABLE,
ERROR_CODE_IO_NETWORK_CONNECTION_FAILED, ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,
ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT, ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT,
ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED,
ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE, ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE,
ERROR_CODE_IO_BAD_HTTP_STATUS, ERROR_CODE_IO_BAD_HTTP_STATUS,
ERROR_CODE_IO_DNS_FAILED,
ERROR_CODE_IO_FILE_NOT_FOUND, ERROR_CODE_IO_FILE_NOT_FOUND,
ERROR_CODE_IO_NO_PERMISSION, ERROR_CODE_IO_NO_PERMISSION,
ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED, ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED,
...@@ -107,32 +105,38 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -107,32 +105,38 @@ public class PlaybackException extends Exception implements Bundleable {
/** Caused by an Input/Output error which could not be identified. */ /** Caused by an Input/Output error which could not be identified. */
public static final int ERROR_CODE_IO_UNSPECIFIED = 2000; public static final int ERROR_CODE_IO_UNSPECIFIED = 2000;
/** Caused by the lack of network connectivity while trying to access a network resource. */ /**
public static final int ERROR_CODE_IO_NETWORK_UNAVAILABLE = 2001; * Caused by a network connection failure.
/** Caused by a failure while establishing a network connection. */ *
public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 2002; * <p>The following is a non-exhaustive list of possible reasons:
*
* <ul>
* <li>There is no network connectivity (you can check this by querying {@link
* ConnectivityManager#getActiveNetwork}).
* <li>The URL's domain is misspelled or does not exist.
* <li>The target host is unreachable.
* <li>The server unexpectedly closes the connection.
* </ul>
*/
public static final int ERROR_CODE_IO_NETWORK_CONNECTION_FAILED = 2001;
/** Caused by a network timeout, meaning the server is taking too long to fulfill a request. */ /** Caused by a network timeout, meaning the server is taking too long to fulfill a request. */
public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 2003; public static final int ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT = 2002;
/** Caused by an existing connection being unexpectedly closed. */
public static final int ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED = 2004;
/** /**
* Caused by a server returning a resource with an invalid "Content-Type" HTTP header value. * Caused by a server returning a resource with an invalid "Content-Type" HTTP header value.
* *
* <p>For example, this can happen when the player is expecting a piece of media, but the server * <p>For example, this can happen when the player is expecting a piece of media, but the server
* returns a paywall HTML page, with content type "text/html". * returns a paywall HTML page, with content type "text/html".
*/ */
public static final int ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE = 2005; public static final int ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE = 2003;
/** Caused by an HTTP server returning an unexpected HTTP response status code. */ /** Caused by an HTTP server returning an unexpected HTTP response status code. */
public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 2006; public static final int ERROR_CODE_IO_BAD_HTTP_STATUS = 2004;
/** Caused by the player failing to resolve a hostname. */
public static final int ERROR_CODE_IO_DNS_FAILED = 2007;
/** Caused by a non-existent file. */ /** Caused by a non-existent file. */
public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 2008; public static final int ERROR_CODE_IO_FILE_NOT_FOUND = 2005;
/** /**
* Caused by lack of permission to perform an IO operation. For example, lack of permission to * Caused by lack of permission to perform an IO operation. For example, lack of permission to
* access internet or external storage. * access internet or external storage.
*/ */
public static final int ERROR_CODE_IO_NO_PERMISSION = 2009; public static final int ERROR_CODE_IO_NO_PERMISSION = 2006;
/** /**
* Caused by the player trying to access cleartext HTTP traffic (meaning http:// rather than * Caused by the player trying to access cleartext HTTP traffic (meaning http:// rather than
* https://) when the app's Network Security Configuration does not permit it. * https://) when the app's Network Security Configuration does not permit it.
...@@ -140,9 +144,9 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -140,9 +144,9 @@ public class PlaybackException extends Exception implements Bundleable {
* <p>See <a href="https://exoplayer.dev/issues/cleartext-not-permitted">this corresponding * <p>See <a href="https://exoplayer.dev/issues/cleartext-not-permitted">this corresponding
* troubleshooting topic</a>. * troubleshooting topic</a>.
*/ */
public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 2010; public static final int ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED = 2007;
/** Caused by reading data out of the data bound. */ /** Caused by reading data out of the data bound. */
public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 2011; public static final int ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE = 2008;
// Content parsing errors (3xxx). // Content parsing errors (3xxx).
...@@ -234,20 +238,14 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -234,20 +238,14 @@ public class PlaybackException extends Exception implements Bundleable {
return "ERROR_CODE_FAILED_RUNTIME_CHECK"; return "ERROR_CODE_FAILED_RUNTIME_CHECK";
case ERROR_CODE_IO_UNSPECIFIED: case ERROR_CODE_IO_UNSPECIFIED:
return "ERROR_CODE_IO_UNSPECIFIED"; return "ERROR_CODE_IO_UNSPECIFIED";
case ERROR_CODE_IO_NETWORK_UNAVAILABLE:
return "ERROR_CODE_IO_NETWORK_UNAVAILABLE";
case ERROR_CODE_IO_NETWORK_CONNECTION_FAILED: case ERROR_CODE_IO_NETWORK_CONNECTION_FAILED:
return "ERROR_CODE_IO_NETWORK_CONNECTION_FAILED"; return "ERROR_CODE_IO_NETWORK_CONNECTION_FAILED";
case ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT: case ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT:
return "ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT"; return "ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT";
case ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED:
return "ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED";
case ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE: case ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE:
return "ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE"; return "ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE";
case ERROR_CODE_IO_BAD_HTTP_STATUS: case ERROR_CODE_IO_BAD_HTTP_STATUS:
return "ERROR_CODE_IO_BAD_HTTP_STATUS"; return "ERROR_CODE_IO_BAD_HTTP_STATUS";
case ERROR_CODE_IO_DNS_FAILED:
return "ERROR_CODE_IO_DNS_FAILED";
case ERROR_CODE_IO_FILE_NOT_FOUND: case ERROR_CODE_IO_FILE_NOT_FOUND:
return "ERROR_CODE_IO_FILE_NOT_FOUND"; return "ERROR_CODE_IO_FILE_NOT_FOUND";
case ERROR_CODE_IO_NO_PERMISSION: case ERROR_CODE_IO_NO_PERMISSION:
......
...@@ -23,11 +23,11 @@ import com.google.android.exoplayer2.util.Util; ...@@ -23,11 +23,11 @@ import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Ascii; import com.google.common.base.Ascii;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import java.io.IOException; import java.io.IOException;
import java.io.InterruptedIOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
...@@ -215,25 +215,21 @@ public interface HttpDataSource extends DataSource { ...@@ -215,25 +215,21 @@ public interface HttpDataSource extends DataSource {
*/ */
public static HttpDataSourceException createForIOException( public static HttpDataSourceException createForIOException(
IOException cause, DataSpec dataSpec, @Type int type) { IOException cause, DataSpec dataSpec, @Type int type) {
@PlaybackException.ErrorCode int errorCode = PlaybackException.ERROR_CODE_IO_UNSPECIFIED; @PlaybackException.ErrorCode int errorCode;
@Nullable String message = cause.getMessage();
if (cause instanceof SocketTimeoutException) { if (cause instanceof SocketTimeoutException) {
errorCode = PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT; errorCode = PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT;
} else if (cause instanceof UnknownHostException) { } else if (cause instanceof InterruptedIOException) {
errorCode = PlaybackException.ERROR_CODE_IO_DNS_FAILED; // An interruption means the operation is being cancelled, in which case this exception
} else { // should not cause the player to fail. If it does, it likely means that the owner of the
@Nullable String message = cause.getMessage(); // operation is failing to swallow the interruption, which makes us enter an invalid state.
if (message != null) { errorCode = PlaybackException.ERROR_CODE_FAILED_RUNTIME_CHECK;
if (Ascii.toLowerCase(message).matches("cleartext.*not permitted.*")) { } else if (message != null
&& Ascii.toLowerCase(message).matches("cleartext.*not permitted.*")) {
errorCode = PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED; errorCode = PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED;
} else if (message.contains("unexpected end of stream")) { } else {
errorCode = PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_CLOSED;
}
}
if (type == TYPE_OPEN && errorCode == PlaybackException.ERROR_CODE_IO_UNSPECIFIED) {
errorCode = PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED; errorCode = PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED;
} }
}
return errorCode == PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED return errorCode == PlaybackException.ERROR_CODE_IO_CLEARTEXT_NOT_PERMITTED
? new CleartextNotPermittedException(cause, dataSpec) ? new CleartextNotPermittedException(cause, dataSpec)
: new HttpDataSourceException(cause, dataSpec, errorCode, type); : new HttpDataSourceException(cause, dataSpec, errorCode, type);
......
...@@ -22,16 +22,12 @@ import androidx.annotation.Nullable; ...@@ -22,16 +22,12 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import java.io.IOException; import java.io.IOException;
import java.net.BindException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.MulticastSocket; import java.net.MulticastSocket;
import java.net.PortUnreachableException;
import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
/** A UDP {@link DataSource}. */ /** A UDP {@link DataSource}. */
public final class UdpDataSource extends BaseDataSource { public final class UdpDataSource extends BaseDataSource {
...@@ -115,25 +111,14 @@ public final class UdpDataSource extends BaseDataSource { ...@@ -115,25 +111,14 @@ public final class UdpDataSource extends BaseDataSource {
} else { } else {
socket = new DatagramSocket(socketAddress); socket = new DatagramSocket(socketAddress);
} }
socket.setSoTimeout(socketTimeoutMillis);
} catch (SecurityException e) { } catch (SecurityException e) {
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_NO_PERMISSION); throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_NO_PERMISSION);
} catch (UnknownHostException e) {
// TODO (internal b/184262323): Handle the case where UnknownHostException is thrown due to
// lack of network access.
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_DNS_FAILED);
} catch (BindException e) {
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_NETWORK_UNAVAILABLE);
} catch (IOException e) { } catch (IOException e) {
throw new UdpDataSourceException( throw new UdpDataSourceException(
e, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED); e, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED);
} }
try {
socket.setSoTimeout(socketTimeoutMillis);
} catch (SocketException e) {
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED);
}
opened = true; opened = true;
transferStarted(dataSpec); transferStarted(dataSpec);
return C.LENGTH_UNSET; return C.LENGTH_UNSET;
...@@ -149,13 +134,12 @@ public final class UdpDataSource extends BaseDataSource { ...@@ -149,13 +134,12 @@ public final class UdpDataSource extends BaseDataSource {
// We've read all of the data from the current packet. Get another. // We've read all of the data from the current packet. Get another.
try { try {
socket.receive(packet); socket.receive(packet);
} catch (PortUnreachableException e) {
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_NETWORK_UNAVAILABLE);
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
throw new UdpDataSourceException( throw new UdpDataSourceException(
e, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT); e, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT);
} catch (IOException e) { } catch (IOException e) {
throw new UdpDataSourceException(e, PlaybackException.ERROR_CODE_IO_UNSPECIFIED); throw new UdpDataSourceException(
e, PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED);
} }
packetRemaining = packet.getLength(); packetRemaining = packet.getLength();
bytesTransferred(packetRemaining); bytesTransferred(packetRemaining);
......
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