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

Commit 0d3b202b authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android Code Review
Browse files

Merge "Fix Memory Leak When Switching Input Methods"

parents 1be46d79 0c33ed29
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -31,9 +31,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    private static final int DO_UPDATE_CURSOR = 95;
    private static final int DO_APP_PRIVATE_COMMAND = 100;
    private static final int DO_TOGGLE_SOFT_INPUT = 105;
    private static final int DO_FINISH_SESSION = 110;

    final HandlerCaller mCaller;
    final InputMethodSession mInputMethodSession;
    HandlerCaller mCaller;
    InputMethodSession mInputMethodSession;
    
    // NOTE: we should have a cache of these.
    static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
@@ -111,6 +112,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
                mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
                return;
            }
            case DO_FINISH_SESSION: {
                mInputMethodSession = null;
                return;
            }
        }
        Log.w(TAG, "Unhandled message code: " + msg.what);
    }
@@ -158,4 +163,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
    public void toggleSoftInput(int showFlags, int hideFlags) {
        mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
    }

    public void finishSession() {
        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
    }
}
+34 −18
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.view.inputmethod.InputMethodSession;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -48,9 +49,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
    private static final int DO_SHOW_SOFT_INPUT = 60;
    private static final int DO_HIDE_SOFT_INPUT = 70;
   
    final AbstractInputMethodService mTarget;
    final WeakReference<AbstractInputMethodService> mTarget;
    final HandlerCaller mCaller;
    final InputMethod mInputMethod;
    final WeakReference<InputMethod> mInputMethod;
    
    static class Notifier {
        boolean notified;
@@ -80,21 +81,32 @@ class IInputMethodWrapper extends IInputMethod.Stub
    
    public IInputMethodWrapper(AbstractInputMethodService context,
            InputMethod inputMethod) {
        mTarget = context;
        mCaller = new HandlerCaller(context, this);
        mInputMethod = inputMethod;
        mTarget = new WeakReference<AbstractInputMethodService>(context);
        mCaller = new HandlerCaller(context.getApplicationContext(), this);
        mInputMethod = new WeakReference<InputMethod>(inputMethod);
    }

    public InputMethod getInternalInputMethod() {
        return mInputMethod;
        return mInputMethod.get();
    }

    public void executeMessage(Message msg) {
        InputMethod inputMethod = mInputMethod.get();
        // Need a valid reference to the inputMethod for everything except a dump.
        if (inputMethod == null && msg.what != DO_DUMP) {
            Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
            return;
        }

        switch (msg.what) {
            case DO_DUMP: {
                AbstractInputMethodService target = mTarget.get();
                if (target == null) {
                    return;
                }
                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
                try {
                    mTarget.dump((FileDescriptor)args.arg1,
                    target.dump((FileDescriptor)args.arg1,
                            (PrintWriter)args.arg2, (String[])args.arg3);
                } catch (RuntimeException e) {
                    ((PrintWriter)args.arg2).println("Exception: " + e);
@@ -106,22 +118,22 @@ class IInputMethodWrapper extends IInputMethod.Stub
            }
            
            case DO_ATTACH_TOKEN: {
                mInputMethod.attachToken((IBinder)msg.obj);
                inputMethod.attachToken((IBinder)msg.obj);
                return;
            }
            case DO_SET_INPUT_CONTEXT: {
                mInputMethod.bindInput((InputBinding)msg.obj);
                inputMethod.bindInput((InputBinding)msg.obj);
                return;
            }
            case DO_UNSET_INPUT_CONTEXT:
                mInputMethod.unbindInput();
                inputMethod.unbindInput();
                return;
            case DO_START_INPUT: {
                HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
                IInputContext inputContext = (IInputContext)args.arg1;
                InputConnection ic = inputContext != null
                        ? new InputConnectionWrapper(inputContext) : null;
                mInputMethod.startInput(ic, (EditorInfo)args.arg2);
                inputMethod.startInput(ic, (EditorInfo)args.arg2);
                return;
            }
            case DO_RESTART_INPUT: {
@@ -129,33 +141,37 @@ class IInputMethodWrapper extends IInputMethod.Stub
                IInputContext inputContext = (IInputContext)args.arg1;
                InputConnection ic = inputContext != null
                        ? new InputConnectionWrapper(inputContext) : null;
                mInputMethod.restartInput(ic, (EditorInfo)args.arg2);
                inputMethod.restartInput(ic, (EditorInfo)args.arg2);
                return;
            }
            case DO_CREATE_SESSION: {
                mInputMethod.createSession(new InputMethodSessionCallbackWrapper(
                inputMethod.createSession(new InputMethodSessionCallbackWrapper(
                        mCaller.mContext, (IInputMethodCallback)msg.obj));
                return;
            }
            case DO_SET_SESSION_ENABLED:
                mInputMethod.setSessionEnabled((InputMethodSession)msg.obj,
                inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
                        msg.arg1 != 0);
                return;
            case DO_REVOKE_SESSION:
                mInputMethod.revokeSession((InputMethodSession)msg.obj);
                inputMethod.revokeSession((InputMethodSession)msg.obj);
                return;
            case DO_SHOW_SOFT_INPUT:
                mInputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                return;
            case DO_HIDE_SOFT_INPUT:
                mInputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                return;
        }
        Log.w(TAG, "Unhandled message code: " + msg.what);
    }
    
    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
        if (mTarget.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
        AbstractInputMethodService target = mTarget.get();
        if (target == null) {
            return;
        }
        if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            
            fout.println("Permission Denial: can't dump InputMethodManager from from pid="
+2 −0
Original line number Diff line number Diff line
@@ -48,4 +48,6 @@ oneway interface IInputMethodSession {
    void appPrivateCommand(String action, in Bundle data);

    void toggleSoftInput(int showFlags, int hideFlags);

    void finishSession();
}
+14 −0
Original line number Diff line number Diff line
@@ -855,12 +855,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        }
    }
    
    private void finishSession(SessionState sessionState) {
        if (sessionState != null && sessionState.session != null) {
            try {
                sessionState.session.finishSession();
            } catch (RemoteException e) {
                Log.w(TAG, "Session failed to close due to remote exception", e);
            }
        }
    }

    void clearCurMethodLocked() {
        if (mCurMethod != null) {
            for (ClientState cs : mClients.values()) {
                cs.sessionRequested = false;
                finishSession(cs.curSession);
                cs.curSession = null;
            }

            finishSession(mEnabledSession);
            mEnabledSession = null;
            mCurMethod = null;
        }
        mStatusBar.setIconVisibility(mInputMethodIcon, false);