OSDN Git Service

Fixing a race condition in RecognitionService
authorValentin Kravtsov <valentink@google.com>
Fri, 18 Feb 2011 12:57:59 +0000 (12:57 +0000)
committerValentin Kravtsov <valentink@google.com>
Wed, 2 Mar 2011 10:16:28 +0000 (10:16 +0000)
Bug #3458256

If an error occurs and simultaneously user cancels the recognition, here is what happens:
1. dispatchCancel() is called since the user requested cancel. It passes the first "if" successfully.

private void dispatchCancel(IRecognitionListener listener) {
       if (mCurrentCallback == null) {
           if (DBG) Log.d(TAG, "cancel called with no preceding startListening - ignoring");
       } else if (mCurrentCallback.mListener.asBinder() != listener.asBinder()) {
           Log.w(TAG, "cancel called by client who did not call startListening - ignoring");
       } else { // the correct state
           RecognitionService.this.onCancel(mCurrentCallback);
           mCurrentCallback = null;
           if (DBG) Log.d(TAG, "canceling - setting mCurrentCallback to null");
       }
   }

2. Error occurs in the app, which sets the mCurrentCallback to null:
       public void error(int error) throws RemoteException {
           mCurrentCallback = null;
           mListener.onError(error);
       }

3. the second "if" is reached in dispatchCancel()
4. boom

Change-Id: I54cdcc98b495d820a2caead1709d8dee968c461e

core/java/android/speech/RecognitionService.java

index 75a5ed5..32b2d8f 100644 (file)
@@ -68,6 +68,8 @@ public abstract class RecognitionService extends Service {
 
     private static final int MSG_CANCEL = 3;
 
+    private static final int MSG_RESET = 4;
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -81,6 +83,10 @@ public abstract class RecognitionService extends Service {
                     break;
                 case MSG_CANCEL:
                     dispatchCancel((IRecognitionListener) msg.obj);
+                    break;
+                case MSG_RESET:
+                    dispatchClearCallback();
+                    break;
             }
         }
     };
@@ -128,6 +134,10 @@ public abstract class RecognitionService extends Service {
         }
     }
 
+    private void dispatchClearCallback() {
+        mCurrentCallback = null;
+    }
+
     private class StartListeningArgs {
         public final Intent mIntent;
 
@@ -241,7 +251,7 @@ public abstract class RecognitionService extends Service {
          * @param error code is defined in {@link SpeechRecognizer}
          */
         public void error(int error) throws RemoteException {
-            mCurrentCallback = null;
+            Message.obtain(mHandler, MSG_RESET).sendToTarget();
             mListener.onError(error);
         }
 
@@ -278,7 +288,7 @@ public abstract class RecognitionService extends Service {
          *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
          */
         public void results(Bundle results) throws RemoteException {
-            mCurrentCallback = null;
+            Message.obtain(mHandler, MSG_RESET).sendToTarget();
             mListener.onResults(results);
         }