From 4cfb3aff8fdaa1bb120065b1caf885c30d3809b6 Mon Sep 17 00:00:00 2001 From: ibaker Date: Mon, 18 Jan 2021 12:26:20 +0000 Subject: [PATCH] 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 --- RELEASENOTES.md | 14 +++++---- .../exoplayer2/drm/DefaultDrmSession.java | 30 +++++++++++++++---- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e19f586b0d..4fb6762088 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -80,8 +80,8 @@ `MediaSourceEventListener` and `SingleSampleMediaSource.Factory` * `SimpleExoPlayer.addVideoDebugListener`, `SimpleExoPlayer.removeVideoDebugListener`, - `SimpleExoPlayer.addAudioDebugListener` - and `SimpleExoPlayer.removeAudioDebugListener`. Use + `SimpleExoPlayer.addAudioDebugListener` and + `SimpleExoPlayer.removeAudioDebugListener`. Use `SimpleExoPlayer.addAnalyticsListener` and `SimpleExoPlayer.removeAnalyticsListener` instead. * `AdaptiveMediaSourceEventListener`. Use `MediaSourceEventListener` @@ -183,6 +183,10 @@ Widevine or Clearkey protected content in a playlist. * Add `ExoMediaDrm.KeyRequest.getRequestType` ([#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: * Pass a `DecoderReuseEvaluation` to `AnalyticsListener`'s `onVideoInputFormatChanged` and `onAudioInputFormatChanged` methods. The @@ -219,9 +223,9 @@ ad view group ([#7344](https://github.com/google/ExoPlayer/issues/7344)), ([#8339](https://github.com/google/ExoPlayer/issues/8339)). - * Fix a bug that could cause the next content position played after a - seek to snap back to the cue point of the preceding ad, rather than - the requested content position. + * Fix a bug that could cause the next content position played after a seek + to snap back to the cue point of the preceding ad, rather than the + requested content position. * FFmpeg extension: * Link the FFmpeg library statically, saving 350KB in binary size on average. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java index 0cec4ab789..f7d7a097a0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java @@ -26,6 +26,7 @@ import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.util.Pair; +import androidx.annotation.GuardedBy; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; 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. state = STATE_RELEASED; Util.castNonNull(responseHandler).removeCallbacksAndMessages(null); - Util.castNonNull(requestHandler).removeCallbacksAndMessages(null); + Util.castNonNull(requestHandler).release(); requestHandler = null; Util.castNonNull(requestHandlerThread).quit(); requestHandlerThread = null; @@ -570,6 +571,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; @SuppressLint("HandlerLeak") private class RequestHandler extends Handler { + @GuardedBy("this") + private boolean isReleased; + public RequestHandler(Looper backgroundLooper) { super(backgroundLooper); } @@ -610,9 +614,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; response = e; } loadErrorHandlingPolicy.onLoadTaskConcluded(requestTask.taskId); - responseHandler - .obtainMessage(msg.what, Pair.create(requestTask.request, response)) - .sendToTarget(); + synchronized (this) { + if (!isReleased) { + responseHandler + .obtainMessage(msg.what, Pair.create(requestTask.request, response)) + .sendToTarget(); + } + } } private boolean maybeRetryRequest(Message originalMsg, MediaDrmCallbackException exception) { @@ -647,8 +655,18 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; // The error is fatal. return false; } - sendMessageDelayed(Message.obtain(originalMsg), retryDelayMs); - return true; + synchronized (this) { + if (!isReleased) { + sendMessageDelayed(Message.obtain(originalMsg), retryDelayMs); + return true; + } + } + return false; + } + + public synchronized void release() { + removeCallbacksAndMessages(/* token= */ null); + isReleased = true; } }