Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96156979 authored by Jeff Brown's avatar Jeff Brown
Browse files

Fix race in RecognizerService teardown.

Use a WeakReference to refer to the outer class to prevent leaks.
Ensure atomicity of access to the reference.

Bug: 17584947
Change-Id: I7ad7c7793b60fa125e04fc4d803ed905e8a00a95
parent 134b62ed
Loading
Loading
Loading
Loading
+19 −11
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.Log;

import java.lang.ref.WeakReference;

/**
 * This class provides a base class for recognition service implementations. This class should be
 * extended only in case you wish to implement a new speech recognizer. Please note that the
@@ -315,40 +317,46 @@ public abstract class RecognitionService extends Service {
    }

    /** Binder of the recognition service */
    private static class RecognitionServiceBinder extends IRecognitionService.Stub {
        private RecognitionService mInternalService;
    private static final class RecognitionServiceBinder extends IRecognitionService.Stub {
        private final WeakReference<RecognitionService> mServiceRef;

        public RecognitionServiceBinder(RecognitionService service) {
            mInternalService = service;
            mServiceRef = new WeakReference<RecognitionService>(service);
        }

        @Override
        public void startListening(Intent recognizerIntent, IRecognitionListener listener) {
            if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder());
            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
                        MSG_START_LISTENING, mInternalService.new StartListeningArgs(
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_START_LISTENING, service.new StartListeningArgs(
                                recognizerIntent, listener)));
            }
        }

        @Override
        public void stopListening(IRecognitionListener listener) {
            if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder());
            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_STOP_LISTENING, listener));
            }
        }

        @Override
        public void cancel(IRecognitionListener listener) {
            if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder());
            if (mInternalService != null && mInternalService.checkPermissions(listener)) {
                mInternalService.mHandler.sendMessage(Message.obtain(mInternalService.mHandler,
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_CANCEL, listener));
            }
        }

        public void clearReference() {
            mInternalService = null;
            mServiceRef.clear();
        }
    }
}