Commit f3189461 by tonihei Committed by Oliver Woodman

Ensure callback can't access player before constructor finished.

If the player is created on a background thread (which is allowed
as the only exception to the access-on-one-thread-only rule), it
may happen that a callback on the main thread tries to access the
player before the constructor even finished. This is dangerous and
can cause exceptions due to uninitialized variables.

To solve this, we can make sure that every player access is blocked
until the constructor finished. Blocking is safe because the
constructor itself is not doing any blocking work or acquiring locks.

The thread verification method is already called on every entry
point to the player, so we can reuse the same method for checking.

PiperOrigin-RevId: 365792949
parent 394ab7bc
......@@ -57,6 +57,7 @@ import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import com.google.android.exoplayer2.util.Util;
......@@ -566,6 +567,7 @@ public class SimpleExoPlayer extends BasePlayer
protected final Renderer[] renderers;
private final ConditionVariable constructorFinished;
private final Context applicationContext;
private final ExoPlayerImpl player;
private final ComponentListener componentListener;
......@@ -635,6 +637,7 @@ public class SimpleExoPlayer extends BasePlayer
/** @param builder The {@link Builder} to obtain all construction parameters. */
protected SimpleExoPlayer(Builder builder) {
constructorFinished = new ConditionVariable();
applicationContext = builder.context.getApplicationContext();
analyticsCollector = builder.analyticsCollector;
priorityTaskManager = builder.priorityTaskManager;
......@@ -718,6 +721,8 @@ public class SimpleExoPlayer extends BasePlayer
sendRendererMessage(C.TRACK_TYPE_VIDEO, Renderer.MSG_SET_SCALING_MODE, videoScalingMode);
sendRendererMessage(
C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_SKIP_SILENCE_ENABLED, skipSilenceEnabled);
constructorFinished.open();
}
@Override
......@@ -1929,6 +1934,9 @@ public class SimpleExoPlayer extends BasePlayer
}
private void verifyApplicationThread() {
// The constructor may be executed on a background thread. Wait with accessing the player from
// the app thread until the constructor finished executing.
constructorFinished.blockUninterruptible();
if (Looper.myLooper() != getApplicationLooper()) {
if (throwsWhenUsingWrongThread) {
throw new IllegalStateException(WRONG_THREAD_ERROR_MESSAGE);
......
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