diff options
| author | 2017-09-29 08:39:17 +0000 | |
|---|---|---|
| committer | 2017-09-29 08:39:17 +0000 | |
| commit | b16c5e91ad87013d723fac22b6b7cc95a768998f (patch) | |
| tree | f8d9b854eaea1c879f244112f51d4b846b6962d4 | |
| parent | 7173362539dcc4b9505066c37c23d1ef22e49c95 (diff) | |
| parent | 407b58aecb8c5edb9c8d980b01d9655d17bdb692 (diff) | |
Merge "NotificationPlayer: fix race conditions" into oc-mr1-dev am: 20e1c66a78
am: 407b58aecb
Change-Id: I24f9e05eaa32d8a3ba007a5785e6d48a86a2c9fe
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java | 74 |
1 files changed, 54 insertions, 20 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java index 50720e9f600f..b5c0d5386767 100644 --- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java @@ -29,6 +29,8 @@ import android.os.PowerManager; import android.os.SystemClock; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.util.LinkedList; /** @@ -57,8 +59,12 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } } - private LinkedList<Command> mCmdQueue = new LinkedList(); + private final LinkedList<Command> mCmdQueue = new LinkedList<Command>(); + private final Object mCompletionHandlingLock = new Object(); + @GuardedBy("mCompletionHandlingLock") + private CreationAndCompletionThread mCompletionThread; + @GuardedBy("mCompletionHandlingLock") private Looper mLooper; /* @@ -76,7 +82,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener public void run() { Looper.prepare(); + // ok to modify mLooper as here we are + // synchronized on mCompletionHandlingLock due to the Object.wait() in startSound(cmd) mLooper = Looper.myLooper(); + if (DEBUG) Log.d(mTag, "in run: new looper " + mLooper); synchronized(this) { AudioManager audioManager = (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE); @@ -97,7 +106,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null) && (mCmd.uri.getEncodedPath().length() > 0)) { if (!audioManager.isMusicActiveRemotely()) { - synchronized(mQueueAudioFocusLock) { + synchronized (mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus == null) { if (DEBUG) Log.d(mTag, "requesting AudioFocus"); int focusGain = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; @@ -129,7 +138,9 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener Log.e(mTag, "Exception while sleeping to sync notification playback" + " with ducking", e); } + if (DEBUG) { Log.d(mTag, "player.start"); } if (mPlayer != null) { + if (DEBUG) { Log.d(mTag, "mPlayer.release"); } mPlayer.release(); } mPlayer = player; @@ -148,7 +159,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener // is playing, let it continue until we're done, so there // is less of a glitch. try { - if (DEBUG) Log.d(mTag, "Starting playback"); + if (DEBUG) { Log.d(mTag, "startSound()"); } //----------------------------------- // This is were we deviate from the AsyncPlayer implementation and create the // MediaPlayer in a new thread with which we're synchronized @@ -158,10 +169,11 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener // matters if((mLooper != null) && (mLooper.getThread().getState() != Thread.State.TERMINATED)) { + if (DEBUG) { Log.d(mTag, "in startSound quitting looper " + mLooper); } mLooper.quit(); } mCompletionThread = new CreationAndCompletionThread(cmd); - synchronized(mCompletionThread) { + synchronized (mCompletionThread) { mCompletionThread.start(); mCompletionThread.wait(); } @@ -209,13 +221,18 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener mPlayer = null; synchronized(mQueueAudioFocusLock) { if (mAudioManagerWithAudioFocus != null) { + if (DEBUG) { Log.d(mTag, "in STOP: abandonning AudioFocus"); } mAudioManagerWithAudioFocus.abandonAudioFocus(null); mAudioManagerWithAudioFocus = null; } } - if((mLooper != null) - && (mLooper.getThread().getState() != Thread.State.TERMINATED)) { - mLooper.quit(); + synchronized (mCompletionHandlingLock) { + if ((mLooper != null) && + (mLooper.getThread().getState() != Thread.State.TERMINATED)) + { + if (DEBUG) { Log.d(mTag, "in STOP: quitting looper "+ mLooper); } + mLooper.quit(); + } } } else { Log.w(mTag, "STOP command without a player"); @@ -250,9 +267,11 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } // if there are no more sounds to play, end the Looper to listen for media completion synchronized (mCmdQueue) { - if (mCmdQueue.size() == 0) { - synchronized(mCompletionHandlingLock) { - if(mLooper != null) { + synchronized(mCompletionHandlingLock) { + if (DEBUG) { Log.d(mTag, "onCompletion queue size=" + mCmdQueue.size()); } + if ((mCmdQueue.size() == 0)) { + if (mLooper != null) { + if (DEBUG) { Log.d(mTag, "in onCompletion quitting looper " + mLooper); } mLooper.quit(); } mCompletionThread = null; @@ -269,13 +288,20 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } private String mTag; + + @GuardedBy("mCmdQueue") private CmdThread mThread; - private CreationAndCompletionThread mCompletionThread; - private final Object mCompletionHandlingLock = new Object(); + private MediaPlayer mPlayer; + + + @GuardedBy("mCmdQueue") private PowerManager.WakeLock mWakeLock; + private final Object mQueueAudioFocusLock = new Object(); - private AudioManager mAudioManagerWithAudioFocus; // synchronized on mQueueAudioFocusLock + @GuardedBy("mQueueAudioFocusLock") + private AudioManager mAudioManagerWithAudioFocus; + private int mNotificationRampTimeMs = 0; // The current state according to the caller. Reality lags behind @@ -311,6 +337,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener */ @Deprecated public void play(Context context, Uri uri, boolean looping, int stream) { + if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); } PlayerBase.deprecateStreamTypeForPlayback(stream, "NotificationPlayer", "play"); Command cmd = new Command(); cmd.requestTime = SystemClock.uptimeMillis(); @@ -339,6 +366,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener * (see {@link MediaPlayer#setAudioAttributes(AudioAttributes)}) */ public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) { + if (DEBUG) { Log.d(mTag, "play uri=" + uri.toString()); } Command cmd = new Command(); cmd.requestTime = SystemClock.uptimeMillis(); cmd.code = PLAY; @@ -357,6 +385,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener * at this point. Calling this multiple times has no ill effects. */ public void stop() { + if (DEBUG) { Log.d(mTag, "stop"); } synchronized (mCmdQueue) { // This check allows stop to be called multiple times without starting // a thread that ends up doing nothing. @@ -370,6 +399,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener } } + @GuardedBy("mCmdQueue") private void enqueueLocked(Command cmd) { mCmdQueue.add(cmd); if (mThread == null) { @@ -393,22 +423,26 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener * @hide */ public void setUsesWakeLock(Context context) { - if (mWakeLock != null || mThread != null) { - // if either of these has happened, we've already played something. - // and our releases will be out of sync. - throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock - + " mThread=" + mThread); + synchronized (mCmdQueue) { + if (mWakeLock != null || mThread != null) { + // if either of these has happened, we've already played something. + // and our releases will be out of sync. + throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock + + " mThread=" + mThread); + } + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); } - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); } + @GuardedBy("mCmdQueue") private void acquireWakeLock() { if (mWakeLock != null) { mWakeLock.acquire(); } } + @GuardedBy("mCmdQueue") private void releaseWakeLock() { if (mWakeLock != null) { mWakeLock.release(); |