Remove ExoPlaybackException.TYPE_OUT_OF_MEMORY
Catching OOM errors is bad practise unless there is a specific known cause that tried to allocate a large amount of memory. Without this known cause with a large allocation, the source of the error is likely somewhere else in the app and every random small further allocation may lead to additional OOM errors (for example b/145134199). We have three known causes in ExoPlayer: 1. Source allocations based on unexpected values in streams. This is caught on the loader thread and reported as an UnexpectedLoaderException. 2. Output buffer allocations by non-MediaCodec decoders. These are caught in SimpleDecoder on the decoder thread and reported as UnexpectedDecodeException. 3. Input buffer allocations by non-MediaCodc decoders in their constructors. These are currently caught on a higher-level and reported as ExoPlaybackException.TYPE_OUT_OF_MEMORY. For consistency and to prevent catching OOM errors without known cause we can remove the generic TYPE_OUT_OF_MEMORY and catch the specific exception where it occurs to report it as an ExoPlaybackException.TYPE_RENDERER. This also has the added advantage that the format metadata is added to the exception. PiperOrigin-RevId: 351326688
This commit is contained in:
parent
b8b9a6411d
commit
c63f3d92ba
@ -42,6 +42,7 @@
|
||||
creating subtitle media sources from
|
||||
`MediaItem.playbackProperties.subtitles`
|
||||
([#8430](https://github.com/google/ExoPlayer/issues/8430)).
|
||||
* Remove `ExoPlaybackException.OutOfMemoryError`.
|
||||
* Extractors:
|
||||
* Populate codecs string for H.264/AVC in MP4, Matroska and FLV streams to
|
||||
allow decoder capability checks based on codec profile/level
|
||||
|
@ -34,20 +34,12 @@ public final class ExoPlaybackException extends Exception {
|
||||
|
||||
/**
|
||||
* The type of source that produced the error. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER}
|
||||
* {@link #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE}, {@link #TYPE_OUT_OF_MEMORY} or {@link
|
||||
* #TYPE_TIMEOUT}. Note that new types may be added in the future and error handling should handle
|
||||
* unknown type values.
|
||||
* {@link #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} or {@link #TYPE_TIMEOUT}. Note that new types
|
||||
* may be added in the future and error handling should handle unknown type values.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
TYPE_SOURCE,
|
||||
TYPE_RENDERER,
|
||||
TYPE_UNEXPECTED,
|
||||
TYPE_REMOTE,
|
||||
TYPE_OUT_OF_MEMORY,
|
||||
TYPE_TIMEOUT
|
||||
})
|
||||
@IntDef({TYPE_SOURCE, TYPE_RENDERER, TYPE_UNEXPECTED, TYPE_REMOTE, TYPE_TIMEOUT})
|
||||
public @interface Type {}
|
||||
/**
|
||||
* The error occurred loading data from a {@code MediaSource}.
|
||||
@ -75,10 +67,9 @@ 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 error was a {@link TimeoutException}. */
|
||||
public static final int TYPE_TIMEOUT = 5;
|
||||
public static final int TYPE_TIMEOUT = 4;
|
||||
|
||||
/** The {@link Type} of the playback failure. */
|
||||
@Type public final int type;
|
||||
@ -175,7 +166,7 @@ public final class ExoPlaybackException extends Exception {
|
||||
* @return The created instance.
|
||||
*/
|
||||
public static ExoPlaybackException createForRenderer(
|
||||
Exception cause,
|
||||
Throwable cause,
|
||||
String rendererName,
|
||||
int rendererIndex,
|
||||
@Nullable Format rendererFormat,
|
||||
@ -202,7 +193,7 @@ public final class ExoPlaybackException extends Exception {
|
||||
* @return The created instance.
|
||||
*/
|
||||
public static ExoPlaybackException createForRenderer(
|
||||
Exception cause,
|
||||
Throwable cause,
|
||||
String rendererName,
|
||||
int rendererIndex,
|
||||
@Nullable Format rendererFormat,
|
||||
@ -240,16 +231,6 @@ 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.
|
||||
*/
|
||||
public static ExoPlaybackException createForOutOfMemory(OutOfMemoryError cause) {
|
||||
return new ExoPlaybackException(TYPE_OUT_OF_MEMORY, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of type {@link #TYPE_TIMEOUT}.
|
||||
*
|
||||
@ -382,16 +363,6 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the underlying error when {@link #type} is {@link #TYPE_TIMEOUT}.
|
||||
*
|
||||
@ -451,9 +422,6 @@ public final class ExoPlaybackException extends Exception {
|
||||
case TYPE_REMOTE:
|
||||
message = "Remote error";
|
||||
break;
|
||||
case TYPE_OUT_OF_MEMORY:
|
||||
message = "Out of memory error";
|
||||
break;
|
||||
case TYPE_TIMEOUT:
|
||||
message = "Timeout error";
|
||||
break;
|
||||
|
@ -340,7 +340,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
||||
* @param format The current format used by the renderer. May be null.
|
||||
*/
|
||||
protected final ExoPlaybackException createRendererException(
|
||||
Exception cause, @Nullable Format format) {
|
||||
Throwable cause, @Nullable Format format) {
|
||||
return createRendererException(cause, format, /* isRecoverable= */ false);
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
||||
* @param isRecoverable If the error is recoverable by disabling and re-enabling the renderer.
|
||||
*/
|
||||
protected final ExoPlaybackException createRendererException(
|
||||
Exception cause, @Nullable Format format, boolean isRecoverable) {
|
||||
Throwable cause, @Nullable Format format, boolean isRecoverable) {
|
||||
@C.FormatSupport int formatSupport = C.FORMAT_HANDLED;
|
||||
if (format != null && !throwRendererExceptionIsExecuting) {
|
||||
// Prevent recursive re-entry from subclass supportsFormat implementations.
|
||||
|
@ -582,11 +582,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
stopInternal(/* forceResetRenderers= */ false, /* acknowledgeStop= */ false);
|
||||
playbackInfo = playbackInfo.copyWithPlaybackError(error);
|
||||
maybeNotifyPlaybackInfoChanged();
|
||||
} catch (RuntimeException | OutOfMemoryError e) {
|
||||
ExoPlaybackException error =
|
||||
e instanceof OutOfMemoryError
|
||||
? ExoPlaybackException.createForOutOfMemory((OutOfMemoryError) e)
|
||||
: ExoPlaybackException.createForUnexpected((RuntimeException) e);
|
||||
} catch (RuntimeException e) {
|
||||
ExoPlaybackException error = ExoPlaybackException.createForUnexpected(e);
|
||||
Log.e(TAG, "Playback error", error);
|
||||
stopInternal(/* forceResetRenderers= */ true, /* acknowledgeStop= */ false);
|
||||
playbackInfo = playbackInfo.copyWithPlaybackError(error);
|
||||
|
@ -619,7 +619,7 @@ public abstract class DecoderAudioRenderer<
|
||||
eventDispatcher.decoderInitialized(decoder.getName(), codecInitializedTimestamp,
|
||||
codecInitializedTimestamp - codecInitializingTimestamp);
|
||||
decoderCounters.decoderInitCount++;
|
||||
} catch (DecoderException e) {
|
||||
} catch (DecoderException | OutOfMemoryError e) {
|
||||
throw createRendererException(e, inputFormat);
|
||||
}
|
||||
}
|
||||
|
@ -707,7 +707,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
||||
decoderInitializedTimestamp,
|
||||
decoderInitializedTimestamp - decoderInitializingTimestamp);
|
||||
decoderCounters.decoderInitCount++;
|
||||
} catch (DecoderException e) {
|
||||
} catch (DecoderException | OutOfMemoryError e) {
|
||||
throw createRendererException(e, inputFormat);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user