Loading core/java/android/speech/tts/TextToSpeechService.java +30 −11 Original line number Diff line number Diff line Loading @@ -502,10 +502,28 @@ public abstract class TextToSpeechService extends Service { return mCurrentSpeechItem; } private synchronized SpeechItem setCurrentSpeechItem(SpeechItem speechItem) { SpeechItem old = mCurrentSpeechItem; private synchronized boolean setCurrentSpeechItem(SpeechItem speechItem) { // Do not set as current if the item has already been flushed. The check is // intentionally put inside this synchronized method. Specifically, the following // racy sequence between this method and stopForApp() needs to be avoided. // (this method) (stopForApp) // 1. isFlushed // 2. startFlushingSpeechItems // 3. maybeRemoveCurrentSpeechItem // 4. set mCurrentSpeechItem // If it happens, stop() is never called on the item. The guard by synchornized(this) // ensures that the step 3 cannot interrupt between 1 and 4. if (speechItem != null && isFlushed(speechItem)) { return false; } mCurrentSpeechItem = speechItem; return old; return true; } private synchronized SpeechItem removeCurrentSpeechItem() { SpeechItem current = mCurrentSpeechItem; mCurrentSpeechItem = null; return current; } private synchronized SpeechItem maybeRemoveCurrentSpeechItem(Object callerIdentity) { Loading @@ -527,7 +545,7 @@ public abstract class TextToSpeechService extends Service { // Don't process any more speech items getLooper().quit(); // Stop the current speech item SpeechItem current = setCurrentSpeechItem(null); SpeechItem current = removeCurrentSpeechItem(); if (current != null) { current.stop(); } Loading Loading @@ -561,12 +579,12 @@ public abstract class TextToSpeechService extends Service { Runnable runnable = new Runnable() { @Override public void run() { if (isFlushed(speechItem)) { speechItem.stop(); } else { setCurrentSpeechItem(speechItem); if (setCurrentSpeechItem(speechItem)) { speechItem.play(); setCurrentSpeechItem(null); removeCurrentSpeechItem(); } else { // The item is alreadly flushed. Stopping. speechItem.stop(); } } }; Loading Loading @@ -600,7 +618,8 @@ public abstract class TextToSpeechService extends Service { return TextToSpeech.ERROR; } // Flush pending messages from callerIdentity // Flush pending messages from callerIdentity. // See setCurrentSpeechItem on a subtlety around a race condition. startFlushingSpeechItems(callerIdentity); // This stops writing data to the file / or publishing Loading Loading @@ -634,7 +653,7 @@ public abstract class TextToSpeechService extends Service { startFlushingSpeechItems(null); // Stop the current speech item unconditionally . SpeechItem current = setCurrentSpeechItem(null); SpeechItem current = removeCurrentSpeechItem(); if (current != null) { current.stop(); } Loading Loading
core/java/android/speech/tts/TextToSpeechService.java +30 −11 Original line number Diff line number Diff line Loading @@ -502,10 +502,28 @@ public abstract class TextToSpeechService extends Service { return mCurrentSpeechItem; } private synchronized SpeechItem setCurrentSpeechItem(SpeechItem speechItem) { SpeechItem old = mCurrentSpeechItem; private synchronized boolean setCurrentSpeechItem(SpeechItem speechItem) { // Do not set as current if the item has already been flushed. The check is // intentionally put inside this synchronized method. Specifically, the following // racy sequence between this method and stopForApp() needs to be avoided. // (this method) (stopForApp) // 1. isFlushed // 2. startFlushingSpeechItems // 3. maybeRemoveCurrentSpeechItem // 4. set mCurrentSpeechItem // If it happens, stop() is never called on the item. The guard by synchornized(this) // ensures that the step 3 cannot interrupt between 1 and 4. if (speechItem != null && isFlushed(speechItem)) { return false; } mCurrentSpeechItem = speechItem; return old; return true; } private synchronized SpeechItem removeCurrentSpeechItem() { SpeechItem current = mCurrentSpeechItem; mCurrentSpeechItem = null; return current; } private synchronized SpeechItem maybeRemoveCurrentSpeechItem(Object callerIdentity) { Loading @@ -527,7 +545,7 @@ public abstract class TextToSpeechService extends Service { // Don't process any more speech items getLooper().quit(); // Stop the current speech item SpeechItem current = setCurrentSpeechItem(null); SpeechItem current = removeCurrentSpeechItem(); if (current != null) { current.stop(); } Loading Loading @@ -561,12 +579,12 @@ public abstract class TextToSpeechService extends Service { Runnable runnable = new Runnable() { @Override public void run() { if (isFlushed(speechItem)) { speechItem.stop(); } else { setCurrentSpeechItem(speechItem); if (setCurrentSpeechItem(speechItem)) { speechItem.play(); setCurrentSpeechItem(null); removeCurrentSpeechItem(); } else { // The item is alreadly flushed. Stopping. speechItem.stop(); } } }; Loading Loading @@ -600,7 +618,8 @@ public abstract class TextToSpeechService extends Service { return TextToSpeech.ERROR; } // Flush pending messages from callerIdentity // Flush pending messages from callerIdentity. // See setCurrentSpeechItem on a subtlety around a race condition. startFlushingSpeechItems(callerIdentity); // This stops writing data to the file / or publishing Loading Loading @@ -634,7 +653,7 @@ public abstract class TextToSpeechService extends Service { startFlushingSpeechItems(null); // Stop the current speech item unconditionally . SpeechItem current = setCurrentSpeechItem(null); SpeechItem current = removeCurrentSpeechItem(); if (current != null) { current.stop(); } Loading