Avoid crashing process on OOM

Catch OutOfMemoryErrors and surface them as unexpected ExoPlaybackExceptions.

PiperOrigin-RevId: 234481140
This commit is contained in:
andrewlewis 2019-02-18 15:50:55 +00:00 committed by Andrew Lewis
parent 0ceff589b3
commit 2b67f2a626
2 changed files with 33 additions and 9 deletions

View file

@ -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}
* or {@link #TYPE_UNEXPECTED}.
* {@link #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} or {@link #TYPE_OUT_OF_MEMORY}.
*/
@Documented
@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 {}
/**
* The error occurred loading data from a {@link MediaSource}.
@ -61,10 +61,12 @@ public final class ExoPlaybackException extends Exception {
* <p>Call {@link #getMessage()} to retrieve the message associated with the error.
*/
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
* {@link #TYPE_UNEXPECTED}.
* The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER}, {@link
* #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} and {@link #TYPE_OUT_OF_MEMORY}.
*/
@Type public final int type;
@ -82,7 +84,7 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance.
*/
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 {
* @return The created instance.
*/
/* 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 {
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) {
super(cause);
this.type = type;
@ -160,4 +172,13 @@ public final class ExoPlaybackException extends Exception {
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);
}
}

View file

@ -389,14 +389,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
/* acknowledgeStop= */ false);
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget();
maybeNotifyPlaybackInfoChanged();
} catch (RuntimeException e) {
} catch (RuntimeException | OutOfMemoryError e) {
Log.e(TAG, "Internal runtime error.", e);
stopInternal(
/* forceResetRenderers= */ true,
/* resetPositionAndState= */ false,
/* acknowledgeStop= */ false);
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForUnexpected(e))
.sendToTarget();
ExoPlaybackException error =
e instanceof OutOfMemoryError
? ExoPlaybackException.createForOutOfMemoryError((OutOfMemoryError) e)
: ExoPlaybackException.createForUnexpected((RuntimeException) e);
eventHandler.obtainMessage(MSG_ERROR, error).sendToTarget();
maybeNotifyPlaybackInfoChanged();
}
return true;