diff options
author | Jean-Michel Trivi <jmtrivi@google.com> | 2009-08-10 16:13:18 -0700 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2009-08-11 15:09:45 -0700 |
commit | 69e67a3e2e863fa8828151ef3a488bfcaa504f7a (patch) | |
tree | fb2a4bdd477897d11f49eab36a0251481759ee72 /packages | |
parent | 021fa3fa6fe88c33ad11a3139ebcd3a5be8eb953 (diff) | |
download | frameworks_base-69e67a3e2e863fa8828151ef3a488bfcaa504f7a.zip frameworks_base-69e67a3e2e863fa8828151ef3a488bfcaa504f7a.tar.gz frameworks_base-69e67a3e2e863fa8828151ef3a488bfcaa504f7a.tar.bz2 |
Fix bug 2043140.
A race condition is encountered when an application invokes shutdown()
on its TextToSpeech object while is has speak() requests still running.
Since the TTS service destructor releases the synthesizer resources and
sets the corresponding synth reference to null, an NPE was observed.
The fix consists in catching NPEs whenever the sNativeSynth object is
accessed, and return the matching error for the call.
This change is a "low risk" version of the fix for bug 2025765i (same
issue) which was reverted because it was higher risk than this CL:
it affected the logic of each call to sNativeSynth. This CL only sets
an error code when an NPE is fired because sNativeSynth is null.
Diffstat (limited to 'packages')
-rwxr-xr-x | packages/TtsService/src/android/tts/TtsService.java | 97 |
1 files changed, 79 insertions, 18 deletions
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java index 1b99d32..cd24727 100755 --- a/packages/TtsService/src/android/tts/TtsService.java +++ b/packages/TtsService/src/android/tts/TtsService.java @@ -172,10 +172,18 @@ public class TtsService extends Service implements OnCompletionListener { @Override public void onDestroy() { super.onDestroy(); + + // TODO replace the call to stopAll() with a method to clear absolutely all upcoming + // uses of the native synth, including synthesis to a file, and delete files for which + // synthesis was not complete. + stopAll(""); + // Don't hog the media player cleanUpPlayer(); - sNativeSynth.shutdown(); + if (sNativeSynth != null) { + sNativeSynth.shutdown(); + } sNativeSynth = null; // Unregister all callbacks. @@ -243,38 +251,70 @@ public class TtsService extends Service implements OnCompletionListener { private int setSpeechRate(String callingApp, int rate) { - if (isDefaultEnforced()) { - return sNativeSynth.setSpeechRate(getDefaultRate()); - } else { - return sNativeSynth.setSpeechRate(rate); + int res = TextToSpeech.ERROR; + try { + if (isDefaultEnforced()) { + res = sNativeSynth.setSpeechRate(getDefaultRate()); + } else { + res = sNativeSynth.setSpeechRate(rate); + } + } catch (NullPointerException e) { + // synth will become null during onDestroy() + res = TextToSpeech.ERROR; } + return res; } private int setPitch(String callingApp, int pitch) { - return sNativeSynth.setPitch(pitch); + int res = TextToSpeech.ERROR; + try { + res = sNativeSynth.setPitch(pitch); + } catch (NullPointerException e) { + // synth will become null during onDestroy() + res = TextToSpeech.ERROR; + } + return res; } private int isLanguageAvailable(String lang, String country, String variant) { //Log.v("TtsService", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")"); - return sNativeSynth.isLanguageAvailable(lang, country, variant); + int res = TextToSpeech.LANG_NOT_SUPPORTED; + try { + res = sNativeSynth.isLanguageAvailable(lang, country, variant); + } catch (NullPointerException e) { + // synth will become null during onDestroy() + res = TextToSpeech.LANG_NOT_SUPPORTED; + } + return res; } private String[] getLanguage() { - return sNativeSynth.getLanguage(); + try { + return sNativeSynth.getLanguage(); + } catch (Exception e) { + return null; + } } private int setLanguage(String callingApp, String lang, String country, String variant) { Log.v("TtsService", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")"); - if (isDefaultEnforced()) { - return sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(), - getDefaultLocVariant()); - } else { - return sNativeSynth.setLanguage(lang, country, variant); + int res = TextToSpeech.ERROR; + try { + if (isDefaultEnforced()) { + res = sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(), + getDefaultLocVariant()); + } else { + res = sNativeSynth.setLanguage(lang, country, variant); + } + } catch (NullPointerException e) { + // synth will become null during onDestroy() + res = TextToSpeech.ERROR; } + return res; } @@ -402,7 +442,12 @@ public class TtsService extends Service implements OnCompletionListener { } if ((mCurrentSpeechItem != null) && mCurrentSpeechItem.mCallingApp.equals(callingApp)) { - result = sNativeSynth.stop(); + try { + result = sNativeSynth.stop(); + } catch (NullPointerException e1) { + // synth will become null during onDestroy() + result = TextToSpeech.ERROR; + } mKillList.put(mCurrentSpeechItem, true); if (mPlayer != null) { try { @@ -434,7 +479,8 @@ public class TtsService extends Service implements OnCompletionListener { /** - * Stops all speech output and removes any utterances still in the queue globally. + * Stops all speech output and removes any utterances still in the queue globally, except + * those intended to be synthesized to file. */ private int stopAll(String callingApp) { int result = TextToSpeech.ERROR; @@ -451,7 +497,12 @@ public class TtsService extends Service implements OnCompletionListener { if ((mCurrentSpeechItem != null) && ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) || mCurrentSpeechItem.mCallingApp.equals(callingApp))) { - result = sNativeSynth.stop(); + try { + result = sNativeSynth.stop(); + } catch (NullPointerException e1) { + // synth will become null during onDestroy() + result = TextToSpeech.ERROR; + } mKillList.put(mCurrentSpeechItem, true); if (mPlayer != null) { try { @@ -591,7 +642,12 @@ public class TtsService extends Service implements OnCompletionListener { if (speechRate.length() > 0){ setSpeechRate("", Integer.parseInt(speechRate)); } - sNativeSynth.speak(speechItem.mText, streamType); + try { + sNativeSynth.speak(speechItem.mText, streamType); + } catch (NullPointerException e) { + // synth will become null during onDestroy() + Log.v("TtsService", " null synth, can't speak"); + } } } catch (InterruptedException e) { Log.e("TtsService", "TTS speakInternalOnly(): tryLock interrupted"); @@ -660,7 +716,12 @@ public class TtsService extends Service implements OnCompletionListener { if (speechRate.length() > 0){ setSpeechRate("", Integer.parseInt(speechRate)); } - sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename); + try { + sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename); + } catch (NullPointerException e) { + // synth will become null during onDestroy() + Log.v("TtsService", " null synth, can't synthesize to file"); + } } } catch (InterruptedException e) { Log.e("TtsService", "TTS synthToFileInternalOnly(): tryLock interrupted"); |