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

Commit 4bcdf9b2 authored by Wilson Wu's avatar Wilson Wu
Browse files

Fix potential failures in InputMethodService (2nd try)

It had the chance for calling into IMS but IMS
already destroyed.

Ideally we should suppress any callbacks after
InputMethodService#onDestroy() and log them.

First try is CL[1], but it wrongly add the API to
IInputMethod. Using the InputMethodServiceInternal
is make more sense for IInputMethodWrapper to
communicate with InputMethodService.

[1]: I10f26a92e739b60c5b8010e8476f8f5a403e0a7b

Bug: 121269861
Bug: 211062619
Bug: 148086656
Test: presubmit
Change-Id: I7b4f34eb38f44dea6872eb46866c9ad7dc1c185c
parent fe8bf190
Loading
Loading
Loading
Loading
+86 −48
Original line number Original line Diff line number Diff line
@@ -147,119 +147,146 @@ class IInputMethodWrapper extends IInputMethod.Stub
    @MainThread
    @MainThread
    @Override
    @Override
    public void executeMessage(Message msg) {
    public void executeMessage(Message msg) {
        InputMethod inputMethod = mInputMethod.get();
        final InputMethod inputMethod = mInputMethod.get();
        // Need a valid reference to the inputMethod for everything except a dump.
        final InputMethodServiceInternal target = mTarget.get();
        if (inputMethod == null && msg.what != DO_DUMP) {
            Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
            return;
        }

        switch (msg.what) {
        switch (msg.what) {
            case DO_DUMP: {
            case DO_DUMP: {
                InputMethodServiceInternal target = mTarget.get();
                if (target == null) {
                    return;
                }
                SomeArgs args = (SomeArgs)msg.obj;
                SomeArgs args = (SomeArgs)msg.obj;
                if (isValid(inputMethod, target, "DO_DUMP")) {
                    final FileDescriptor fd = (FileDescriptor) args.arg1;
                    final PrintWriter fout = (PrintWriter) args.arg2;
                    final String[] dumpArgs = (String[]) args.arg3;
                    final CountDownLatch latch = (CountDownLatch) args.arg4;
                    try {
                    try {
                    target.dump((FileDescriptor) args.arg1,
                        target.dump(fd, fout, dumpArgs);
                            (PrintWriter) args.arg2, (String[]) args.arg3);
                    } catch (RuntimeException e) {
                    } catch (RuntimeException e) {
                    ((PrintWriter)args.arg2).println("Exception: " + e);
                        fout.println("Exception: " + e);
                    } finally {
                        latch.countDown();
                    }
                    }
                synchronized (args.arg4) {
                    ((CountDownLatch)args.arg4).countDown();
                }
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_INITIALIZE_INTERNAL:
            case DO_INITIALIZE_INTERNAL:
                if (isValid(inputMethod, target, "DO_INITIALIZE_INTERNAL")) {
                    inputMethod.initializeInternal((IInputMethod.InitParams) msg.obj);
                    inputMethod.initializeInternal((IInputMethod.InitParams) msg.obj);
                }
                return;
                return;
            case DO_SET_INPUT_CONTEXT: {
            case DO_SET_INPUT_CONTEXT: {
                if (isValid(inputMethod, target, "DO_SET_INPUT_CONTEXT")) {
                    inputMethod.bindInput((InputBinding) msg.obj);
                    inputMethod.bindInput((InputBinding) msg.obj);
                }
                return;
                return;
            }
            }
            case DO_UNSET_INPUT_CONTEXT:
            case DO_UNSET_INPUT_CONTEXT:
                if (isValid(inputMethod, target, "DO_UNSET_INPUT_CONTEXT")) {
                    inputMethod.unbindInput();
                    inputMethod.unbindInput();
                }
                return;
                return;
            case DO_START_INPUT: {
            case DO_START_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final SomeArgs args = (SomeArgs) msg.obj;
                if (isValid(inputMethod, target, "DO_START_INPUT")) {
                    final InputConnection inputConnection = (InputConnection) args.arg1;
                    final InputConnection inputConnection = (InputConnection) args.arg1;
                    final IInputMethod.StartInputParams params =
                    final IInputMethod.StartInputParams params =
                            (IInputMethod.StartInputParams) args.arg2;
                            (IInputMethod.StartInputParams) args.arg2;
                    inputMethod.dispatchStartInput(inputConnection, params);
                    inputMethod.dispatchStartInput(inputConnection, params);
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_ON_NAV_BUTTON_FLAGS_CHANGED:
            case DO_ON_NAV_BUTTON_FLAGS_CHANGED:
                if (isValid(inputMethod, target, "DO_ON_NAV_BUTTON_FLAGS_CHANGED")) {
                    inputMethod.onNavButtonFlagsChanged(msg.arg1);
                    inputMethod.onNavButtonFlagsChanged(msg.arg1);
                }
                return;
                return;
            case DO_CREATE_SESSION: {
            case DO_CREATE_SESSION: {
                SomeArgs args = (SomeArgs)msg.obj;
                SomeArgs args = (SomeArgs)msg.obj;
                if (isValid(inputMethod, target, "DO_CREATE_SESSION")) {
                    inputMethod.createSession(new InputMethodSessionCallbackWrapper(
                    inputMethod.createSession(new InputMethodSessionCallbackWrapper(
                            mContext, (InputChannel) args.arg1,
                            mContext, (InputChannel) args.arg1,
                            (IInputMethodSessionCallback) args.arg2));
                            (IInputMethodSessionCallback) args.arg2));
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_SET_SESSION_ENABLED:
            case DO_SET_SESSION_ENABLED:
                inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
                if (isValid(inputMethod, target, "DO_SET_SESSION_ENABLED")) {
                        msg.arg1 != 0);
                    inputMethod.setSessionEnabled((InputMethodSession) msg.obj, msg.arg1 != 0);
                }
                return;
                return;
            case DO_SHOW_SOFT_INPUT: {
            case DO_SHOW_SOFT_INPUT: {
                final SomeArgs args = (SomeArgs)msg.obj;
                final SomeArgs args = (SomeArgs)msg.obj;
                if (isValid(inputMethod, target, "DO_SHOW_SOFT_INPUT")) {
                    inputMethod.showSoftInputWithToken(
                    inputMethod.showSoftInputWithToken(
                            msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
                            msg.arg1, (ResultReceiver) args.arg2, (IBinder) args.arg1);
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_HIDE_SOFT_INPUT: {
            case DO_HIDE_SOFT_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final SomeArgs args = (SomeArgs) msg.obj;
                if (isValid(inputMethod, target, "DO_HIDE_SOFT_INPUT")) {
                    inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
                    inputMethod.hideSoftInputWithToken(msg.arg1, (ResultReceiver) args.arg2,
                            (IBinder) args.arg1);
                            (IBinder) args.arg1);
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_CHANGE_INPUTMETHOD_SUBTYPE:
            case DO_CHANGE_INPUTMETHOD_SUBTYPE:
                if (isValid(inputMethod, target, "DO_CHANGE_INPUTMETHOD_SUBTYPE")) {
                    inputMethod.changeInputMethodSubtype((InputMethodSubtype) msg.obj);
                    inputMethod.changeInputMethodSubtype((InputMethodSubtype) msg.obj);
                }
                return;
                return;
            case DO_CREATE_INLINE_SUGGESTIONS_REQUEST: {
            case DO_CREATE_INLINE_SUGGESTIONS_REQUEST: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final SomeArgs args = (SomeArgs) msg.obj;
                if (isValid(inputMethod, target, "DO_CREATE_INLINE_SUGGESTIONS_REQUEST")) {
                    inputMethod.onCreateInlineSuggestionsRequest(
                    inputMethod.onCreateInlineSuggestionsRequest(
                            (InlineSuggestionsRequestInfo) args.arg1,
                            (InlineSuggestionsRequestInfo) args.arg1,
                            (IInlineSuggestionsRequestCallback) args.arg2);
                            (IInlineSuggestionsRequestCallback) args.arg2);
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_CAN_START_STYLUS_HANDWRITING: {
            case DO_CAN_START_STYLUS_HANDWRITING: {
                if (isValid(inputMethod, target, "DO_CAN_START_STYLUS_HANDWRITING")) {
                    inputMethod.canStartStylusHandwriting(msg.arg1);
                    inputMethod.canStartStylusHandwriting(msg.arg1);
                }
                return;
                return;
            }
            }
            case DO_UPDATE_TOOL_TYPE: {
            case DO_UPDATE_TOOL_TYPE: {
                if (isValid(inputMethod, target, "DO_UPDATE_TOOL_TYPE")) {
                    inputMethod.updateEditorToolType(msg.arg1);
                    inputMethod.updateEditorToolType(msg.arg1);
                }
                return;
                return;
            }
            }
            case DO_START_STYLUS_HANDWRITING: {
            case DO_START_STYLUS_HANDWRITING: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final SomeArgs args = (SomeArgs) msg.obj;
                if (isValid(inputMethod, target, "DO_START_STYLUS_HANDWRITING")) {
                    inputMethod.startStylusHandwriting(msg.arg1, (InputChannel) args.arg1,
                    inputMethod.startStylusHandwriting(msg.arg1, (InputChannel) args.arg1,
                            (List<MotionEvent>) args.arg2);
                            (List<MotionEvent>) args.arg2);
                }
                args.recycle();
                args.recycle();
                return;
                return;
            }
            }
            case DO_INIT_INK_WINDOW: {
            case DO_INIT_INK_WINDOW: {
                if (isValid(inputMethod, target, "DO_INIT_INK_WINDOW")) {
                    inputMethod.initInkWindow();
                    inputMethod.initInkWindow();
                }
                return;
                return;
            }
            }
            case DO_FINISH_STYLUS_HANDWRITING: {
            case DO_FINISH_STYLUS_HANDWRITING: {
                if (isValid(inputMethod, target, "DO_FINISH_STYLUS_HANDWRITING")) {
                    inputMethod.finishStylusHandwriting();
                    inputMethod.finishStylusHandwriting();
                }
                return;
                return;
            }
            }
            case DO_REMOVE_STYLUS_HANDWRITING_WINDOW: {
            case DO_REMOVE_STYLUS_HANDWRITING_WINDOW: {
                if (isValid(inputMethod, target, "DO_REMOVE_STYLUS_HANDWRITING_WINDOW")) {
                    inputMethod.removeStylusHandwritingWindow();
                    inputMethod.removeStylusHandwritingWindow();
                }
                return;
                return;
            }
            }

        }
        }
        Log.w(TAG, "Unhandled message code: " + msg.what);
        Log.w(TAG, "Unhandled message code: " + msg.what);
    }
    }
@@ -445,4 +472,15 @@ class IInputMethodWrapper extends IInputMethod.Stub
    public void removeStylusHandwritingWindow() {
    public void removeStylusHandwritingWindow() {
        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_STYLUS_HANDWRITING_WINDOW));
        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_STYLUS_HANDWRITING_WINDOW));
    }
    }

    private static boolean isValid(InputMethod inputMethod, InputMethodServiceInternal target,
            String msg) {
        if (inputMethod != null && target != null && !target.isServiceDestroyed()) {
            return true;
        } else {
            Log.w(TAG, "Ignoring " + msg + ", InputMethod:" + inputMethod
                    + ", InputMethodServiceInternal:" + target);
            return false;
        }
    }
}
}
+8 −5
Original line number Original line Diff line number Diff line
@@ -700,11 +700,6 @@ public class InputMethodService extends AbstractInputMethodService {
        @MainThread
        @MainThread
        @Override
        @Override
        public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
        public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
            if (mDestroyed) {
                Log.i(TAG, "The InputMethodService has already onDestroyed()."
                    + "Ignore the initialization.");
                return;
            }
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
            mConfigTracker.onInitialize(params.configChanges);
            mConfigTracker.onInitialize(params.configChanges);
            mPrivOps.set(params.privilegedOperations);
            mPrivOps.set(params.privilegedOperations);
@@ -3938,6 +3933,14 @@ public class InputMethodService extends AbstractInputMethodService {
            public void triggerServiceDump(String where, @Nullable byte[] icProto) {
            public void triggerServiceDump(String where, @Nullable byte[] icProto) {
                ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto);
                ImeTracing.getInstance().triggerServiceDump(where, mDumper, icProto);
            }
            }

            /**
             * {@inheritDoc}
             */
            @Override
            public boolean isServiceDestroyed() {
                return mDestroyed;
            }
        };
        };
    }
    }


+7 −0
Original line number Original line Diff line number Diff line
@@ -85,4 +85,11 @@ interface InputMethodServiceInternal {
     */
     */
    default void triggerServiceDump(@NonNull String where, @Nullable byte[] icProto) {
    default void triggerServiceDump(@NonNull String where, @Nullable byte[] icProto) {
    }
    }

    /**
     * @return {@code true} if {@link InputMethodService} is destroyed.
     */
    default boolean isServiceDestroyed() {
        return false;
    };
}
}