Drop responses in DefaultDrmSession if the session has been released

This prevents trying to post the response to possibly dead threads,
which causes an IllegalStateException to be logged.

Issue: #8328
PiperOrigin-RevId: 352388155
This commit is contained in:
ibaker 2021-01-18 12:26:20 +00:00 committed by Oliver Woodman
parent 61cf97a0c0
commit 4cfb3aff8f
2 changed files with 33 additions and 11 deletions

View file

@ -80,8 +80,8 @@
`MediaSourceEventListener` and `SingleSampleMediaSource.Factory` `MediaSourceEventListener` and `SingleSampleMediaSource.Factory`
* `SimpleExoPlayer.addVideoDebugListener`, * `SimpleExoPlayer.addVideoDebugListener`,
`SimpleExoPlayer.removeVideoDebugListener`, `SimpleExoPlayer.removeVideoDebugListener`,
`SimpleExoPlayer.addAudioDebugListener` `SimpleExoPlayer.addAudioDebugListener` and
and `SimpleExoPlayer.removeAudioDebugListener`. Use `SimpleExoPlayer.removeAudioDebugListener`. Use
`SimpleExoPlayer.addAnalyticsListener` and `SimpleExoPlayer.addAnalyticsListener` and
`SimpleExoPlayer.removeAnalyticsListener` instead. `SimpleExoPlayer.removeAnalyticsListener` instead.
* `AdaptiveMediaSourceEventListener`. Use `MediaSourceEventListener` * `AdaptiveMediaSourceEventListener`. Use `MediaSourceEventListener`
@ -183,6 +183,10 @@
Widevine or Clearkey protected content in a playlist. Widevine or Clearkey protected content in a playlist.
* Add `ExoMediaDrm.KeyRequest.getRequestType` * Add `ExoMediaDrm.KeyRequest.getRequestType`
([#7847](https://github.com/google/ExoPlayer/issues/7847)). ([#7847](https://github.com/google/ExoPlayer/issues/7847)).
* Drop key & provision responses if `DefaultDrmSession` is released while
waiting for the response. This fixes (harmless) `IllegalStateException:
sending message to a Handler on a dead thread` log messages
([#8328](https://github.com/google/ExoPlayer/issues/8328)).
* Analytics: * Analytics:
* Pass a `DecoderReuseEvaluation` to `AnalyticsListener`'s * Pass a `DecoderReuseEvaluation` to `AnalyticsListener`'s
`onVideoInputFormatChanged` and `onAudioInputFormatChanged` methods. The `onVideoInputFormatChanged` and `onAudioInputFormatChanged` methods. The
@ -219,9 +223,9 @@
ad view group ad view group
([#7344](https://github.com/google/ExoPlayer/issues/7344)), ([#7344](https://github.com/google/ExoPlayer/issues/7344)),
([#8339](https://github.com/google/ExoPlayer/issues/8339)). ([#8339](https://github.com/google/ExoPlayer/issues/8339)).
* Fix a bug that could cause the next content position played after a * Fix a bug that could cause the next content position played after a seek
seek to snap back to the cue point of the preceding ad, rather than to snap back to the cue point of the preceding ad, rather than the
the requested content position. requested content position.
* FFmpeg extension: * FFmpeg extension:
* Link the FFmpeg library statically, saving 350KB in binary size on * Link the FFmpeg library statically, saving 350KB in binary size on
average. average.

View file

@ -26,6 +26,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
@ -308,7 +309,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
// Assigning null to various non-null variables for clean-up. // Assigning null to various non-null variables for clean-up.
state = STATE_RELEASED; state = STATE_RELEASED;
Util.castNonNull(responseHandler).removeCallbacksAndMessages(null); Util.castNonNull(responseHandler).removeCallbacksAndMessages(null);
Util.castNonNull(requestHandler).removeCallbacksAndMessages(null); Util.castNonNull(requestHandler).release();
requestHandler = null; requestHandler = null;
Util.castNonNull(requestHandlerThread).quit(); Util.castNonNull(requestHandlerThread).quit();
requestHandlerThread = null; requestHandlerThread = null;
@ -570,6 +571,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
private class RequestHandler extends Handler { private class RequestHandler extends Handler {
@GuardedBy("this")
private boolean isReleased;
public RequestHandler(Looper backgroundLooper) { public RequestHandler(Looper backgroundLooper) {
super(backgroundLooper); super(backgroundLooper);
} }
@ -610,9 +614,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
response = e; response = e;
} }
loadErrorHandlingPolicy.onLoadTaskConcluded(requestTask.taskId); loadErrorHandlingPolicy.onLoadTaskConcluded(requestTask.taskId);
responseHandler synchronized (this) {
.obtainMessage(msg.what, Pair.create(requestTask.request, response)) if (!isReleased) {
.sendToTarget(); responseHandler
.obtainMessage(msg.what, Pair.create(requestTask.request, response))
.sendToTarget();
}
}
} }
private boolean maybeRetryRequest(Message originalMsg, MediaDrmCallbackException exception) { private boolean maybeRetryRequest(Message originalMsg, MediaDrmCallbackException exception) {
@ -647,8 +655,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
// The error is fatal. // The error is fatal.
return false; return false;
} }
sendMessageDelayed(Message.obtain(originalMsg), retryDelayMs); synchronized (this) {
return true; if (!isReleased) {
sendMessageDelayed(Message.obtain(originalMsg), retryDelayMs);
return true;
}
}
return false;
}
public synchronized void release() {
removeCallbacksAndMessages(/* token= */ null);
isReleased = true;
} }
} }