Commit 2b67f2a6 by andrewlewis Committed by Andrew Lewis

Avoid crashing process on OOM

Catch OutOfMemoryErrors and surface them as unexpected ExoPlaybackExceptions.

PiperOrigin-RevId: 234481140
parent 0ceff589
...@@ -31,11 +31,11 @@ public final class ExoPlaybackException extends Exception { ...@@ -31,11 +31,11 @@ public final class ExoPlaybackException extends Exception {
/** /**
* The type of source that produced the error. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER} * The type of source that produced the error. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER}
* or {@link #TYPE_UNEXPECTED}. * {@link #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} or {@link #TYPE_OUT_OF_MEMORY}.
*/ */
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_SOURCE, TYPE_RENDERER, TYPE_UNEXPECTED, TYPE_REMOTE}) @IntDef({TYPE_SOURCE, TYPE_RENDERER, TYPE_UNEXPECTED, TYPE_REMOTE, TYPE_OUT_OF_MEMORY})
public @interface Type {} public @interface Type {}
/** /**
* The error occurred loading data from a {@link MediaSource}. * The error occurred loading data from a {@link MediaSource}.
...@@ -61,10 +61,12 @@ public final class ExoPlaybackException extends Exception { ...@@ -61,10 +61,12 @@ public final class ExoPlaybackException extends Exception {
* <p>Call {@link #getMessage()} to retrieve the message associated with the error. * <p>Call {@link #getMessage()} to retrieve the message associated with the error.
*/ */
public static final int TYPE_REMOTE = 3; public static final int TYPE_REMOTE = 3;
/** The error was an {@link OutOfMemoryError}. */
public static final int TYPE_OUT_OF_MEMORY = 4;
/** /**
* The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER} and * The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER}, {@link
* {@link #TYPE_UNEXPECTED}. * #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} and {@link #TYPE_OUT_OF_MEMORY}.
*/ */
@Type public final int type; @Type public final int type;
...@@ -82,7 +84,7 @@ public final class ExoPlaybackException extends Exception { ...@@ -82,7 +84,7 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance. * @return The created instance.
*/ */
public static ExoPlaybackException createForSource(IOException cause) { public static ExoPlaybackException createForSource(IOException cause) {
return new ExoPlaybackException(TYPE_SOURCE, cause, C.INDEX_UNSET); return new ExoPlaybackException(TYPE_SOURCE, cause, /* rendererIndex= */ C.INDEX_UNSET);
} }
/** /**
...@@ -103,7 +105,7 @@ public final class ExoPlaybackException extends Exception { ...@@ -103,7 +105,7 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance. * @return The created instance.
*/ */
/* package */ static ExoPlaybackException createForUnexpected(RuntimeException cause) { /* package */ static ExoPlaybackException createForUnexpected(RuntimeException cause) {
return new ExoPlaybackException(TYPE_UNEXPECTED, cause, C.INDEX_UNSET); return new ExoPlaybackException(TYPE_UNEXPECTED, cause, /* rendererIndex= */ C.INDEX_UNSET);
} }
/** /**
...@@ -116,6 +118,16 @@ public final class ExoPlaybackException extends Exception { ...@@ -116,6 +118,16 @@ public final class ExoPlaybackException extends Exception {
return new ExoPlaybackException(TYPE_REMOTE, message); return new ExoPlaybackException(TYPE_REMOTE, message);
} }
/**
* Creates an instance of type {@link #TYPE_OUT_OF_MEMORY}.
*
* @param cause The cause of the failure.
* @return The created instance.
*/
/* package */ static ExoPlaybackException createForOutOfMemoryError(OutOfMemoryError cause) {
return new ExoPlaybackException(TYPE_OUT_OF_MEMORY, cause, /* rendererIndex= */ C.INDEX_UNSET);
}
private ExoPlaybackException(@Type int type, Throwable cause, int rendererIndex) { private ExoPlaybackException(@Type int type, Throwable cause, int rendererIndex) {
super(cause); super(cause);
this.type = type; this.type = type;
...@@ -160,4 +172,13 @@ public final class ExoPlaybackException extends Exception { ...@@ -160,4 +172,13 @@ public final class ExoPlaybackException extends Exception {
return (RuntimeException) Assertions.checkNotNull(cause); return (RuntimeException) Assertions.checkNotNull(cause);
} }
/**
* Retrieves the underlying error when {@link #type} is {@link #TYPE_OUT_OF_MEMORY}.
*
* @throws IllegalStateException If {@link #type} is not {@link #TYPE_OUT_OF_MEMORY}.
*/
public OutOfMemoryError getOutOfMemoryError() {
Assertions.checkState(type == TYPE_OUT_OF_MEMORY);
return (OutOfMemoryError) Assertions.checkNotNull(cause);
}
} }
...@@ -389,14 +389,17 @@ import java.util.concurrent.atomic.AtomicBoolean; ...@@ -389,14 +389,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
/* acknowledgeStop= */ false); /* acknowledgeStop= */ false);
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget(); eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget();
maybeNotifyPlaybackInfoChanged(); maybeNotifyPlaybackInfoChanged();
} catch (RuntimeException e) { } catch (RuntimeException | OutOfMemoryError e) {
Log.e(TAG, "Internal runtime error.", e); Log.e(TAG, "Internal runtime error.", e);
stopInternal( stopInternal(
/* forceResetRenderers= */ true, /* forceResetRenderers= */ true,
/* resetPositionAndState= */ false, /* resetPositionAndState= */ false,
/* acknowledgeStop= */ false); /* acknowledgeStop= */ false);
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForUnexpected(e)) ExoPlaybackException error =
.sendToTarget(); e instanceof OutOfMemoryError
? ExoPlaybackException.createForOutOfMemoryError((OutOfMemoryError) e)
: ExoPlaybackException.createForUnexpected((RuntimeException) e);
eventHandler.obtainMessage(MSG_ERROR, error).sendToTarget();
maybeNotifyPlaybackInfoChanged(); maybeNotifyPlaybackInfoChanged();
} }
return true; return true;
......
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