summaryrefslogtreecommitdiffstats
path: root/packages/TtsService/src/android/tts/TtsService.java
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2009-08-03 10:50:51 -0700
committerJean-Michel Trivi <jmtrivi@google.com>2009-08-03 11:07:46 -0700
commit9ebb59b8aa75cab1e5bb53983893b579abb63edd (patch)
tree2e1397154b6779735bf0d5b963a726f505cad374 /packages/TtsService/src/android/tts/TtsService.java
parentc134c281ca83a28deb96c7b338c48c0b0327f26f (diff)
downloadframeworks_base-9ebb59b8aa75cab1e5bb53983893b579abb63edd.zip
frameworks_base-9ebb59b8aa75cab1e5bb53983893b579abb63edd.tar.gz
frameworks_base-9ebb59b8aa75cab1e5bb53983893b579abb63edd.tar.bz2
Fix bug 2025765.
Talkback produced a null pointer exception when being enabled and disabled repeatedly due to a race condition between the onDestroy() of the service, and the use of the service itself. The error occurs when one Talkback thread initiates the destruction of the service (call to onDestroy()) when it invokes shutdown() on its TextToSpeech instance (the client of the service). At the same time, Talkback tries to say that "Accessibility" is unchecked from another thread. During onDestroy(), the reference to the TTS engine (sNativeSynth) is reset to null, which is used in the service in speakInternalOnly(), and setLanguage(). The fix consists in the addition of a static variable that signals that the service has entered onDestroy(). Once this flag is set, all method invocations on sNativeSynth will be dismissed. Note that access to the native resources used by sNativeSynth are synchronized at the native layer, therefore preventing sNativeSynth.shutdown() to interfere with a sNativeSynth.speak() call already underway.
Diffstat (limited to 'packages/TtsService/src/android/tts/TtsService.java')
-rwxr-xr-xpackages/TtsService/src/android/tts/TtsService.java46
1 files changed, 42 insertions, 4 deletions
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 1b99d32..70960b5 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -142,6 +142,8 @@ public class TtsService extends Service implements OnCompletionListener {
private final ReentrantLock synthesizerLock = new ReentrantLock();
private static SynthProxy sNativeSynth = null;
+ private static Boolean sIsKillingSynth = true;
+
@Override
public void onCreate() {
super.onCreate();
@@ -152,6 +154,7 @@ public class TtsService extends Service implements OnCompletionListener {
String soLibPath = "/system/lib/libttspico.so";
if (sNativeSynth == null) {
sNativeSynth = new SynthProxy(soLibPath);
+ sIsKillingSynth = false;
}
mSelf = this;
@@ -172,6 +175,9 @@ public class TtsService extends Service implements OnCompletionListener {
@Override
public void onDestroy() {
super.onDestroy();
+
+ sIsKillingSynth = true;
+ Log.i("TtsService", "TtsService.onDestroy()");
// Don't hog the media player
cleanUpPlayer();
@@ -180,6 +186,7 @@ public class TtsService extends Service implements OnCompletionListener {
// Unregister all callbacks.
mCallbacks.kill();
+ //Log.i("TtsService", "TtsService.onDestroy() ended");
}
@@ -243,6 +250,9 @@ public class TtsService extends Service implements OnCompletionListener {
private int setSpeechRate(String callingApp, int rate) {
+ if (sIsKillingSynth) {
+ return TextToSpeech.ERROR;
+ }
if (isDefaultEnforced()) {
return sNativeSynth.setSpeechRate(getDefaultRate());
} else {
@@ -252,23 +262,37 @@ public class TtsService extends Service implements OnCompletionListener {
private int setPitch(String callingApp, int pitch) {
+ if (sIsKillingSynth) {
+ return TextToSpeech.ERROR;
+ }
return sNativeSynth.setPitch(pitch);
}
private int isLanguageAvailable(String lang, String country, String variant) {
+ if (sIsKillingSynth) {
+ return TextToSpeech.LANG_NOT_SUPPORTED;
+ }
//Log.v("TtsService", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")");
return sNativeSynth.isLanguageAvailable(lang, country, variant);
}
private String[] getLanguage() {
+ if (sIsKillingSynth) {
+ Log.v("TtsService", "killing synth:: aborting getLanguage()");
+ return null;
+ }
return sNativeSynth.getLanguage();
}
private int setLanguage(String callingApp, String lang, String country, String variant) {
Log.v("TtsService", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
+ if (sIsKillingSynth) {
+ Log.v("TtsService", "killing synth:: aborting setLanguage()");
+ return TextToSpeech.ERROR;
+ }
if (isDefaultEnforced()) {
return sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
getDefaultLocVariant());
@@ -402,7 +426,12 @@ public class TtsService extends Service implements OnCompletionListener {
}
if ((mCurrentSpeechItem != null) &&
mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
- result = sNativeSynth.stop();
+ if (sIsKillingSynth) {
+ Log.v("TtsService", "killing synth:: aborting stop()");
+ result = TextToSpeech.ERROR;
+ } else {
+ result = sNativeSynth.stop();
+ }
mKillList.put(mCurrentSpeechItem, true);
if (mPlayer != null) {
try {
@@ -451,7 +480,12 @@ public class TtsService extends Service implements OnCompletionListener {
if ((mCurrentSpeechItem != null) &&
((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
- result = sNativeSynth.stop();
+ if (sIsKillingSynth) {
+ Log.v("TtsService", "killing synth:: aborting stop()");
+ result = TextToSpeech.ERROR;
+ } else {
+ result = sNativeSynth.stop();
+ }
mKillList.put(mCurrentSpeechItem, true);
if (mPlayer != null) {
try {
@@ -591,7 +625,9 @@ public class TtsService extends Service implements OnCompletionListener {
if (speechRate.length() > 0){
setSpeechRate("", Integer.parseInt(speechRate));
}
- sNativeSynth.speak(speechItem.mText, streamType);
+ if (!sIsKillingSynth) {
+ sNativeSynth.speak(speechItem.mText, streamType);
+ }
}
} catch (InterruptedException e) {
Log.e("TtsService", "TTS speakInternalOnly(): tryLock interrupted");
@@ -660,7 +696,9 @@ public class TtsService extends Service implements OnCompletionListener {
if (speechRate.length() > 0){
setSpeechRate("", Integer.parseInt(speechRate));
}
- sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
+ if (!sIsKillingSynth) {
+ sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
+ }
}
} catch (InterruptedException e) {
Log.e("TtsService", "TTS synthToFileInternalOnly(): tryLock interrupted");