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

Commit 0fee8d10 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Clarify which InputMethodManagerInternal method takes lock internally

InputMethodManagerInternal is the callback where we need to pay extra
attention to potential dead-locks.

To make code reading easier, this CL makes it clear about which method
needs to acquire ImfLock and which method is always thread-safe.

Basically this is a mechanical code refactoring.  There should be no
observable behavior change.

Bug: 192412909
Test: presubmit
Change-Id: I98958e6c149582b0a24997c9ca814e355f8b2a2b
parent 052cb99b
Loading
Loading
Loading
Loading
+91 −120
Original line number Diff line number Diff line
@@ -1495,8 +1495,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub

        @Override
        public void onStart() {
            LocalServices.addService(InputMethodManagerInternal.class,
                    new LocalServiceImpl(mService));
            mService.publishLocalService();
            publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
        }
@@ -4866,26 +4865,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        return mCurrentSubtype;
    }

    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
        synchronized (ImfLock.class) {
            return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
        }
    }

    private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
        synchronized (ImfLock.class) {
            return getEnabledInputMethodListLocked(userId);
        }
    }

    private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
            InlineSuggestionsRequestInfo requestInfo,
            IInlineSuggestionsRequestCallback callback) {
        synchronized (ImfLock.class) {
            onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
        }
    }

    private ArrayMap<String, InputMethodInfo> queryMethodMapForUser(@UserIdInt int userId) {
        final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
        final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
@@ -4897,8 +4876,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        return methodMap;
    }

    private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
        synchronized (ImfLock.class) {
    @GuardedBy("ImfLock.class")
    private boolean switchToInputMethodLocked(String imeId, @UserIdInt int userId) {
        if (userId == mSettings.getCurrentUserId()) {
            if (!mMethodMap.containsKey(imeId)
                    || !mSettings.getEnabledInputMethodListLocked()
@@ -4921,9 +4900,56 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
        settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
        return true;
    }

    private void publishLocalService() {
        LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl());
    }

    private final class LocalServiceImpl extends InputMethodManagerInternal {

        @Override
        public void setInteractive(boolean interactive) {
            // Do everything in handler so as not to block the caller.
            mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0).sendToTarget();
        }

        @Override
        public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
            mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
            mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
        }

        @Override
        public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
            synchronized (ImfLock.class) {
                return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
            }
        }

    private boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
        @Override
        public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
            synchronized (ImfLock.class) {
                return getEnabledInputMethodListLocked(userId);
            }
        }

        @Override
        public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
                InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
            synchronized (ImfLock.class) {
                onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb);
            }
        }

        @Override
        public boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
            synchronized (ImfLock.class) {
                return switchToInputMethodLocked(imeId, userId);
            }
        }

        @Override
        public boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
            synchronized (ImfLock.class) {
                if (userId == mSettings.getCurrentUserId()) {
                    if (!mMethodMap.containsKey(imeId)) {
@@ -4940,7 +4966,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                    return false; // IME is not found.
                }
                if (enabled) {
                if (!settings.getEnabledInputMethodListLocked().contains(methodMap.get(imeId))) {
                    if (!settings.getEnabledInputMethodListLocked().contains(
                            methodMap.get(imeId))) {
                        settings.appendAndPutEnabledInputMethodLocked(imeId, false);
                    }
                } else {
@@ -4952,7 +4979,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            }
        }

    private boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
        @Override
        public void registerInputMethodListListener(InputMethodListListener listener) {
            mInputMethodListListeners.addIfAbsent(listener);
        }

        @Override
        public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
                int displayId) {
            //TODO(b/150843766): Check if Input Token is valid.
            final IBinder curHostInputToken;
@@ -4965,11 +4998,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
        }

    private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
        @Override
        public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
            synchronized (ImfLock.class) {
                if (mCurFocusedWindow != windowToken) {
                // mCurPerceptible was set by the focused window, but it is no longer in control,
                // so we reset mCurPerceptible.
                    // mCurPerceptible was set by the focused window, but it is no longer in
                    // control, so we reset mCurPerceptible.
                    mCurPerceptible = true;
                }
                if (imeParentChanged) {
@@ -4981,77 +5015,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
            }
        }

    private static final class LocalServiceImpl extends InputMethodManagerInternal {
        @NonNull
        private final InputMethodManagerService mService;

        LocalServiceImpl(@NonNull InputMethodManagerService service) {
            mService = service;
        }

        @Override
        public void setInteractive(boolean interactive) {
            // Do everything in handler so as not to block the caller.
            mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
                    .sendToTarget();
        }

        @Override
        public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
            mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
            mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
        }

        @Override
        public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
            return mService.getInputMethodListAsUser(userId);
        }

        @Override
        public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
            return mService.getEnabledInputMethodListAsUser(userId);
        }

        @Override
        public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
                InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
            mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb);
        }

        @Override
        public boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
            return mService.switchToInputMethod(imeId, userId);
        }

        @Override
        public boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
            return mService.setInputMethodEnabled(imeId, enabled, userId);
        }

        @Override
        public void registerInputMethodListListener(InputMethodListListener listener) {
            mService.mInputMethodListListeners.addIfAbsent(listener);
        }

        @Override
        public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
                int displayId) {
            return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId);
        }

        @Override
        public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
            mService.reportImeControl(windowToken, imeParentChanged);
        }

        @Override
        public void removeImeSurface() {
            mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();
            mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();
        }

        @Override
        public void updateImeWindowStatus(boolean disableImeIcon) {
            mService.mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
            mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
                    .sendToTarget();
        }
    }
@@ -5689,7 +5660,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
                if (!userHasDebugPriv(userId, shellCommand)) {
                    continue;
                }
                boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
                boolean failedToSelectUnknownIme = !switchToInputMethodLocked(imeId, userId);
                if (failedToSelectUnknownIme) {
                    error.print("Unknown input method ");
                    error.print(imeId);