diff options
3 files changed, 588 insertions, 144 deletions
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java new file mode 100644 index 000000000000..7890fe0ed461 --- /dev/null +++ b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.inputmethod; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.Manifest; +import android.annotation.BinderThread; +import android.annotation.EnforcePermission; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.os.Binder; +import android.os.IBinder; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.view.MotionEvent; +import android.view.WindowManager; +import android.view.inputmethod.CursorAnchorInfo; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.ImeTracker; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; +import android.window.ImeOnBackInvokedDispatcher; + +import com.android.internal.inputmethod.DirectBootAwareness; +import com.android.internal.inputmethod.IBooleanListener; +import com.android.internal.inputmethod.IConnectionlessHandwritingCallback; +import com.android.internal.inputmethod.IImeTracker; +import com.android.internal.inputmethod.IInputMethodClient; +import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; +import com.android.internal.inputmethod.IRemoteInputConnection; +import com.android.internal.inputmethod.InputBindResult; +import com.android.internal.inputmethod.SoftInputShowHideReason; +import com.android.internal.inputmethod.StartInputFlags; +import com.android.internal.inputmethod.StartInputReason; +import com.android.internal.view.IInputMethodManager; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.List; + +/** + * An actual implementation class of {@link IInputMethodManager.Stub} to allow other classes to + * focus on handling IPC callbacks. + */ +final class IInputMethodManagerImpl extends IInputMethodManager.Stub { + + /** + * Tells that the given permission is already verified before the annotated method gets called. + */ + @Retention(SOURCE) + @Target({METHOD}) + @interface PermissionVerified { + String value() default ""; + } + + @BinderThread + interface Callback { + void addClient(IInputMethodClient client, IRemoteInputConnection inputConnection, + int selfReportedDisplayId); + + InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId); + + List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, + @DirectBootAwareness int directBootAwareness); + + List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId); + + List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, + boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId); + + InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId); + + boolean showSoftInput(IInputMethodClient client, IBinder windowToken, + @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, + @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason); + + boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, + @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason); + + @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) + void hideSoftInputFromServerForTest(); + + void startInputOrWindowGainedFocusAsync( + @StartInputReason int startInputReason, IInputMethodClient client, + IBinder windowToken, @StartInputFlags int startInputFlags, + @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, + @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, + IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, + int unverifiedTargetSdkVersion, @UserIdInt int userId, + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq); + + InputBindResult startInputOrWindowGainedFocus( + @StartInputReason int startInputReason, IInputMethodClient client, + IBinder windowToken, @StartInputFlags int startInputFlags, + @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, + @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, + IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, + int unverifiedTargetSdkVersion, @UserIdInt int userId, + @NonNull ImeOnBackInvokedDispatcher imeDispatcher); + + void showInputMethodPickerFromClient(IInputMethodClient client, int auxiliarySubtypeMode); + + @PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS) + void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId); + + @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) + boolean isInputMethodPickerShownForTest(); + + InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId); + + void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes, + @UserIdInt int userId); + + void setExplicitlyEnabledInputMethodSubtypes(String imeId, + @NonNull int[] subtypeHashCodes, @UserIdInt int userId); + + int getInputMethodWindowVisibleHeight(IInputMethodClient client); + + void reportPerceptibleAsync(IBinder windowToken, boolean perceptible); + + @PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + void removeImeSurface(); + + void removeImeSurfaceFromWindowAsync(IBinder windowToken); + + void startProtoDump(byte[] bytes, int i, String s); + + boolean isImeTraceEnabled(); + + @PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) + void startImeTrace(); + + @PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) + void stopImeTrace(); + + void startStylusHandwriting(IInputMethodClient client); + + void startConnectionlessStylusHandwriting(IInputMethodClient client, @UserIdInt int userId, + @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, + @Nullable String delegatorPackageName, + @NonNull IConnectionlessHandwritingCallback callback); + + boolean acceptStylusHandwritingDelegation(@NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, + @NonNull String delegatorPackageName, + @InputMethodManager.HandwritingDelegateFlags int flags); + + void acceptStylusHandwritingDelegationAsync(@NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, + @NonNull String delegatorPackageName, + @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback); + + void prepareStylusHandwritingDelegation(@NonNull IInputMethodClient client, + @UserIdInt int userId, @NonNull String delegatePackageName, + @NonNull String delegatorPackageName); + + boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId, boolean connectionless); + + @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) + void addVirtualStylusIdForTestSession(IInputMethodClient client); + + @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) + void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout); + + IImeTracker getImeTrackerService(); + + void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, + @Nullable FileDescriptor err, @NonNull String[] args, + @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver, + @NonNull Binder self); + + void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args); + } + + @NonNull + private final Callback mCallback; + + private IInputMethodManagerImpl(@NonNull Callback callback) { + mCallback = callback; + } + + static IInputMethodManagerImpl create(@NonNull Callback callback) { + return new IInputMethodManagerImpl(callback); + } + + @Override + public void addClient(IInputMethodClient client, IRemoteInputConnection inputmethod, + int untrustedDisplayId) { + mCallback.addClient(client, inputmethod, untrustedDisplayId); + } + + @Override + public InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId) { + return mCallback.getCurrentInputMethodInfoAsUser(userId); + } + + @Override + public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, + int directBootAwareness) { + return mCallback.getInputMethodList(userId, directBootAwareness); + } + + @Override + public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) { + return mCallback.getEnabledInputMethodList(userId); + } + + @Override + public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, + boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) { + return mCallback.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes, + userId); + } + + @Override + public InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId) { + return mCallback.getLastInputMethodSubtype(userId); + } + + @Override + public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, + @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, + @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason) { + return mCallback.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType, + resultReceiver, reason); + } + + @Override + public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, + @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { + return mCallback.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver, + reason); + } + + @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @Override + public void hideSoftInputFromServerForTest() { + super.hideSoftInputFromServerForTest_enforcePermission(); + + mCallback.hideSoftInputFromServerForTest(); + } + + @Override + public InputBindResult startInputOrWindowGainedFocus( + @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken, + @StartInputFlags int startInputFlags, + @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, + int windowFlags, @Nullable EditorInfo editorInfo, + IRemoteInputConnection inputConnection, + IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, + int unverifiedTargetSdkVersion, @UserIdInt int userId, + @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { + return mCallback.startInputOrWindowGainedFocus( + startInputReason, client, windowToken, startInputFlags, softInputMode, + windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, + unverifiedTargetSdkVersion, userId, imeDispatcher); + } + + @Override + public void startInputOrWindowGainedFocusAsync(@StartInputReason int startInputReason, + IInputMethodClient client, IBinder windowToken, + @StartInputFlags int startInputFlags, + @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, + int windowFlags, @Nullable EditorInfo editorInfo, + IRemoteInputConnection inputConnection, + IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, + int unverifiedTargetSdkVersion, @UserIdInt int userId, + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) { + mCallback.startInputOrWindowGainedFocusAsync( + startInputReason, client, windowToken, startInputFlags, softInputMode, + windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, + unverifiedTargetSdkVersion, userId, imeDispatcher, startInputSeq); + } + + @Override + public void showInputMethodPickerFromClient(IInputMethodClient client, + int auxiliarySubtypeMode) { + mCallback.showInputMethodPickerFromClient(client, auxiliarySubtypeMode); + } + + @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @Override + public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { + super.showInputMethodPickerFromSystem_enforcePermission(); + + mCallback.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId); + + } + + @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @Override + public boolean isInputMethodPickerShownForTest() { + super.isInputMethodPickerShownForTest_enforcePermission(); + + return mCallback.isInputMethodPickerShownForTest(); + } + + @Override + public InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) { + return mCallback.getCurrentInputMethodSubtype(userId); + } + + @Override + public void setAdditionalInputMethodSubtypes(String id, InputMethodSubtype[] subtypes, + @UserIdInt int userId) { + mCallback.setAdditionalInputMethodSubtypes(id, subtypes, userId); + } + + @Override + public void setExplicitlyEnabledInputMethodSubtypes(String imeId, int[] subtypeHashCodes, + @UserIdInt int userId) { + mCallback.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); + } + + @Override + public int getInputMethodWindowVisibleHeight(IInputMethodClient client) { + return mCallback.getInputMethodWindowVisibleHeight(client); + } + + @Override + public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) { + mCallback.reportPerceptibleAsync(windowToken, perceptible); + } + + @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + @Override + public void removeImeSurface() { + super.removeImeSurface_enforcePermission(); + + mCallback.removeImeSurface(); + } + + @Override + public void removeImeSurfaceFromWindowAsync(IBinder windowToken) { + mCallback.removeImeSurfaceFromWindowAsync(windowToken); + } + + @Override + public void startProtoDump(byte[] protoDump, int source, String where) { + mCallback.startProtoDump(protoDump, source, where); + } + + @Override + public boolean isImeTraceEnabled() { + return mCallback.isImeTraceEnabled(); + } + + @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @Override + public void startImeTrace() { + super.startImeTrace_enforcePermission(); + + mCallback.startImeTrace(); + } + + @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @Override + public void stopImeTrace() { + super.stopImeTrace_enforcePermission(); + + mCallback.stopImeTrace(); + } + + @Override + public void startStylusHandwriting(IInputMethodClient client) { + mCallback.startStylusHandwriting(client); + } + + @Override + public void startConnectionlessStylusHandwriting(IInputMethodClient client, + @UserIdInt int userId, CursorAnchorInfo cursorAnchorInfo, + String delegatePackageName, String delegatorPackageName, + IConnectionlessHandwritingCallback callback) { + mCallback.startConnectionlessStylusHandwriting(client, userId, cursorAnchorInfo, + delegatePackageName, delegatorPackageName, callback); + } + + @Override + public void prepareStylusHandwritingDelegation(IInputMethodClient client, @UserIdInt int userId, + String delegatePackageName, String delegatorPackageName) { + mCallback.prepareStylusHandwritingDelegation(client, userId, + delegatePackageName, delegatorPackageName); + } + + @Override + public boolean acceptStylusHandwritingDelegation(IInputMethodClient client, + @UserIdInt int userId, String delegatePackageName, String delegatorPackageName, + @InputMethodManager.HandwritingDelegateFlags int flags) { + return mCallback.acceptStylusHandwritingDelegation(client, userId, + delegatePackageName, delegatorPackageName, flags); + } + + @Override + public void acceptStylusHandwritingDelegationAsync(IInputMethodClient client, + @UserIdInt int userId, String delegatePackageName, String delegatorPackageName, + @InputMethodManager.HandwritingDelegateFlags int flags, + IBooleanListener callback) { + mCallback.acceptStylusHandwritingDelegationAsync(client, userId, + delegatePackageName, delegatorPackageName, flags, callback); + } + + @Override + public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId, + boolean connectionless) { + return mCallback.isStylusHandwritingAvailableAsUser(userId, connectionless); + } + + @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @Override + public void addVirtualStylusIdForTestSession(IInputMethodClient client) { + super.addVirtualStylusIdForTestSession_enforcePermission(); + + mCallback.addVirtualStylusIdForTestSession(client); + } + + @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @Override + public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) { + super.setStylusWindowIdleTimeoutForTest_enforcePermission(); + + mCallback.setStylusWindowIdleTimeoutForTest(client, timeout); + } + + @Override + public IImeTracker getImeTrackerService() { + return mCallback.getImeTrackerService(); + } + + @Override + public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, + @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, + @NonNull ResultReceiver resultReceiver) { + mCallback.onShellCommand(in, out, err, args, callback, resultReceiver, this); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mCallback.dump(fd, pw, args); + } +} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1d07eee927b2..03a85c40ef31 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -61,7 +61,6 @@ import android.annotation.AnyThread; import android.annotation.BinderThread; import android.annotation.DrawableRes; import android.annotation.DurationMillisLong; -import android.annotation.EnforcePermission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -172,7 +171,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; -import com.android.internal.view.IInputMethodManager; import com.android.server.AccessibilityManagerInternal; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -211,8 +209,9 @@ import java.util.function.IntConsumer; /** * This class provides a system service that manages input methods. */ -public final class InputMethodManagerService extends IInputMethodManager.Stub - implements Handler.Callback { +public final class InputMethodManagerService implements IInputMethodManagerImpl.Callback, + ZeroJankProxy.Callback, Handler.Callback { + // Virtual device id for test. private static final Integer VIRTUAL_STYLUS_ID_FOR_TEST = 999999; static final boolean DEBUG = false; @@ -1236,21 +1235,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onStart() { mService.publishLocalService(); - IInputMethodManager.Stub service; + IInputMethodManagerImpl.Callback service; if (Flags.useZeroJankProxy()) { - service = - new ZeroJankProxy( - mService.mHandler::post, - mService, - () -> { - synchronized (ImfLock.class) { - return mService.isInputShown(); - } - }); + service = new ZeroJankProxy(mService.mHandler::post, mService); } else { service = mService; } - publishBinderService(Context.INPUT_METHOD_SERVICE, service, false /*allowIsolated*/, + publishBinderService(Context.INPUT_METHOD_SERVICE, + IInputMethodManagerImpl.create(service), false /*allowIsolated*/, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO); } @@ -1935,10 +1927,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @Nullable - ClientState getClientState(IInputMethodClient client) { - synchronized (ImfLock.class) { - return mClientController.getClient(client.asBinder()); - } + @GuardedBy("ImfLock.class") + @Override + public ClientState getClientStateLocked(IInputMethodClient client) { + return mClientController.getClient(client.asBinder()); } // TODO(b/314150112): Move this to ClientController. @@ -2017,7 +2009,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("ImfLock.class") - private boolean isInputShown() { + @Override + public boolean isInputShownLocked() { return mVisibilityStateComputer.isInputShown(); } @@ -3133,11 +3126,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub public void startConnectionlessStylusHandwriting(IInputMethodClient client, int userId, @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, @Nullable String delegatorPackageName, - @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException { + @NonNull IConnectionlessHandwritingCallback callback) { synchronized (ImfLock.class) { if (!mBindingController.supportsConnectionlessStylusHandwriting()) { Slog.w(TAG, "Connectionless stylus handwriting mode unsupported by IME."); - callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED); + try { + callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED", e); + e.rethrowAsRuntimeException(); + } return; } } @@ -3148,7 +3146,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub synchronized (ImfLock.class) { if (!mClientController.verifyClientAndPackageMatch(client, delegatorPackageName)) { Slog.w(TAG, "startConnectionlessStylusHandwriting() fail"); - callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); + try { + callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_OTHER", e); + e.rethrowAsRuntimeException(); + } throw new IllegalArgumentException("Delegator doesn't match UID"); } } @@ -3172,7 +3175,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (!startStylusHandwriting( client, false, immsCallback, cursorAnchorInfo, isForDelegation)) { - callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); + try { + callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_OTHER", e); + e.rethrowAsRuntimeException(); + } } } @@ -3272,11 +3280,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, - @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) - throws RemoteException { + @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) { boolean result = acceptStylusHandwritingDelegation( client, userId, delegatePackageName, delegatorPackageName, flags); - callback.onResult(result); + try { + callback.onResult(result); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report result=" + result, e); + e.rethrowAsRuntimeException(); + } } @Override @@ -3367,7 +3379,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @GuardedBy("ImfLock.class") boolean showCurrentInputLocked(IBinder windowToken, @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, - int lastClickToolType, @Nullable ResultReceiver resultReceiver, + @MotionEvent.ToolType int lastClickToolType, @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) { return false; @@ -3413,7 +3425,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub "InputMethodManagerService#hideSoftInput"); synchronized (ImfLock.class) { if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) { - if (isInputShown()) { + if (isInputShownLocked()) { ImeTracker.forLogging().onFailed( statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED); } else { @@ -3436,10 +3448,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @Override - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) public void hideSoftInputFromServerForTest() { - super.hideSoftInputFromServerForTest_enforcePermission(); - synchronized (ImfLock.class) { hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */, SoftInputShowHideReason.HIDE_SOFT_INPUT); @@ -3472,7 +3482,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // TODO(b/246309664): Clean up IMMS#mImeWindowVis IInputMethodInvoker curMethod = getCurMethodLocked(); final boolean shouldHideSoftInput = curMethod != null - && (isInputShown() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); + && (isInputShownLocked() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); mVisibilityStateComputer.requestImeVisibility(windowToken, false); if (shouldHideSoftInput) { @@ -3845,13 +3855,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } - @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS) @Override public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { // Always call subtype picker, because subtype picker is a superset of input method // picker. - super.showInputMethodPickerFromSystem_enforcePermission(); - mHandler.obtainMessage(MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId) .sendToTarget(); } @@ -3859,10 +3867,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub /** * A test API for CTS to make sure that the input method menu is showing. */ - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShownForTest() { - super.isInputMethodPickerShownForTest_enforcePermission(); - synchronized (ImfLock.class) { return mMenuController.isisInputMethodPickerShownForTestLocked(); } @@ -4162,11 +4168,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub }); } - @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW) @Override public void removeImeSurface() { - super.removeImeSurface_enforcePermission(); - mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget(); } @@ -4275,11 +4279,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * a stylus deviceId is not already registered on device. */ @BinderThread - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) @Override public void addVirtualStylusIdForTestSession(IInputMethodClient client) { - super.addVirtualStylusIdForTestSession_enforcePermission(); - int uid = Binder.getCallingUid(); synchronized (ImfLock.class) { if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession", @@ -4302,12 +4304,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * @param timeout to set in milliseconds. To reset to default, use a value <= zero. */ @BinderThread - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) @Override public void setStylusWindowIdleTimeoutForTest( IInputMethodClient client, @DurationMillisLong long timeout) { - super.setStylusWindowIdleTimeoutForTest_enforcePermission(); - int uid = Binder.getCallingUid(); synchronized (ImfLock.class) { if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest", @@ -4403,10 +4403,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @BinderThread - @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) @Override public void startImeTrace() { - super.startImeTrace_enforcePermission(); ImeTracing.getInstance().startTrace(null /* printwriter */); synchronized (ImfLock.class) { mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(true /* enabled */)); @@ -4414,11 +4413,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @BinderThread - @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) @Override public void stopImeTrace() { - super.stopImeTrace_enforcePermission(); - ImeTracing.getInstance().stopTrace(null /* printwriter */); synchronized (ImfLock.class) { mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(false /* enabled */)); @@ -4698,7 +4695,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // implemented so that auxiliary subtypes will be excluded when the soft // keyboard is invisible. synchronized (ImfLock.class) { - showAuxSubtypes = isInputShown(); + showAuxSubtypes = isInputShownLocked(); } break; case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES: @@ -5845,7 +5842,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub @BinderThread @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; PriorityDump.dump(mPriorityDumper, fd, pw, args); @@ -5975,7 +5972,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, - @NonNull ResultReceiver resultReceiver) throws RemoteException { + @NonNull ResultReceiver resultReceiver, @NonNull Binder self) { final int callingUid = Binder.getCallingUid(); // Reject any incoming calls from non-shell users, including ones from the system user. if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { @@ -5996,7 +5993,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub throw new SecurityException(errorMsg); } new ShellCommandImpl(this).exec( - this, in, out, err, args, callback, resultReceiver); + self, in, out, err, args, callback, resultReceiver); } private static final class ShellCommandImpl extends ShellCommand { diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java index ffc2319b60af..1cd1ddce78fd 100644 --- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java +++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java @@ -36,17 +36,16 @@ import static com.android.server.inputmethod.InputMethodManagerService.TAG; import android.Manifest; import android.annotation.BinderThread; -import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.os.Binder; import android.os.IBinder; -import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.Slog; +import android.view.MotionEvent; import android.view.WindowManager; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; @@ -56,6 +55,7 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import android.window.ImeOnBackInvokedDispatcher; +import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.IBooleanListener; import com.android.internal.inputmethod.IConnectionlessHandwritingCallback; @@ -76,22 +76,25 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; -import java.util.function.BooleanSupplier; /** * A proxy that processes all {@link IInputMethodManager} calls asynchronously. - * @hide */ -public class ZeroJankProxy extends IInputMethodManager.Stub { +final class ZeroJankProxy implements IInputMethodManagerImpl.Callback { - private final IInputMethodManager mInner; + interface Callback extends IInputMethodManagerImpl.Callback { + @GuardedBy("ImfLock.class") + ClientState getClientStateLocked(IInputMethodClient client); + @GuardedBy("ImfLock.class") + boolean isInputShownLocked(); + } + + private final Callback mInner; private final Executor mExecutor; - private final BooleanSupplier mIsInputShown; - ZeroJankProxy(Executor executor, IInputMethodManager inner, BooleanSupplier isInputShown) { + ZeroJankProxy(Executor executor, Callback inner) { mInner = inner; mExecutor = executor; - mIsInputShown = isInputShown; } private void offload(ThrowingRunnable r) { @@ -126,45 +129,43 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { @Override public void addClient(IInputMethodClient client, IRemoteInputConnection inputConnection, - int selfReportedDisplayId) throws RemoteException { + int selfReportedDisplayId) { offload(() -> mInner.addClient(client, inputConnection, selfReportedDisplayId)); } @Override - public InputMethodInfo getCurrentInputMethodInfoAsUser(int userId) throws RemoteException { + public InputMethodInfo getCurrentInputMethodInfoAsUser(int userId) { return mInner.getCurrentInputMethodInfoAsUser(userId); } @Override public List<InputMethodInfo> getInputMethodList( - int userId, @DirectBootAwareness int directBootAwareness) throws RemoteException { + int userId, @DirectBootAwareness int directBootAwareness) { return mInner.getInputMethodList(userId, directBootAwareness); } @Override - public List<InputMethodInfo> getEnabledInputMethodList(int userId) throws RemoteException { + public List<InputMethodInfo> getEnabledInputMethodList(int userId) { return mInner.getEnabledInputMethodList(userId); } @Override public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, - boolean allowsImplicitlyEnabledSubtypes, int userId) - throws RemoteException { + boolean allowsImplicitlyEnabledSubtypes, int userId) { return mInner.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes, userId); } @Override - public InputMethodSubtype getLastInputMethodSubtype(int userId) throws RemoteException { + public InputMethodSubtype getLastInputMethodSubtype(int userId) { return mInner.getLastInputMethodSubtype(userId); } @Override public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, - int lastClickTooType, ResultReceiver resultReceiver, - @SoftInputShowHideReason int reason) - throws RemoteException { + @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, + @SoftInputShowHideReason int reason) { offload( () -> { if (!mInner.showSoftInput( @@ -172,7 +173,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { windowToken, statsToken, flags, - lastClickTooType, + lastClickToolType, resultReceiver, reason)) { sendResultReceiverFailure(resultReceiver); @@ -184,8 +185,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { @Override public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, - ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) - throws RemoteException { + ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { offload( () -> { if (!mInner.hideSoftInput( @@ -200,17 +200,19 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { if (resultReceiver == null) { return; } - resultReceiver.send( - mIsInputShown.getAsBoolean() + final boolean isInputShown; + synchronized (ImfLock.class) { + isInputShown = mInner.isInputShownLocked(); + } + resultReceiver.send(isInputShown ? InputMethodManager.RESULT_UNCHANGED_SHOWN : InputMethodManager.RESULT_UNCHANGED_HIDDEN, null); } @Override - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) - public void hideSoftInputFromServerForTest() throws RemoteException { - super.hideSoftInputFromServerForTest_enforcePermission(); + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) + public void hideSoftInputFromServerForTest() { mInner.hideSoftInputFromServerForTest(); } @@ -225,8 +227,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) - throws RemoteException { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) { offload(() -> { InputBindResult result = mInner.startInputOrWindowGainedFocus(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, @@ -249,99 +250,92 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { IRemoteInputConnection inputConnection, IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, int unverifiedTargetSdkVersion, @UserIdInt int userId, - @NonNull ImeOnBackInvokedDispatcher imeDispatcher) - throws RemoteException { + @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { // Should never be called when flag is enabled i.e. when this proxy is used. return null; } @Override public void showInputMethodPickerFromClient(IInputMethodClient client, - int auxiliarySubtypeMode) - throws RemoteException { + int auxiliarySubtypeMode) { offload(() -> mInner.showInputMethodPickerFromClient(client, auxiliarySubtypeMode)); } - @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS) @Override - public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) - throws RemoteException { + public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { mInner.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId); } - @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) @Override - public boolean isInputMethodPickerShownForTest() throws RemoteException { - super.isInputMethodPickerShownForTest_enforcePermission(); + public boolean isInputMethodPickerShownForTest() { return mInner.isInputMethodPickerShownForTest(); } @Override - public InputMethodSubtype getCurrentInputMethodSubtype(int userId) throws RemoteException { + public InputMethodSubtype getCurrentInputMethodSubtype(int userId) { return mInner.getCurrentInputMethodSubtype(userId); } @Override public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes, - @UserIdInt int userId) throws RemoteException { + @UserIdInt int userId) { mInner.setAdditionalInputMethodSubtypes(imiId, subtypes, userId); } @Override public void setExplicitlyEnabledInputMethodSubtypes(String imeId, - @NonNull int[] subtypeHashCodes, @UserIdInt int userId) throws RemoteException { + @NonNull int[] subtypeHashCodes, @UserIdInt int userId) { mInner.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); } @Override - public int getInputMethodWindowVisibleHeight(IInputMethodClient client) - throws RemoteException { + public int getInputMethodWindowVisibleHeight(IInputMethodClient client) { return mInner.getInputMethodWindowVisibleHeight(client); } @Override - public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) - throws RemoteException { + public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) { // Already async TODO(b/293640003): ordering issues? mInner.reportPerceptibleAsync(windowToken, perceptible); } - @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW) @Override - public void removeImeSurface() throws RemoteException { + public void removeImeSurface() { mInner.removeImeSurface(); } @Override - public void removeImeSurfaceFromWindowAsync(IBinder windowToken) throws RemoteException { + public void removeImeSurfaceFromWindowAsync(IBinder windowToken) { mInner.removeImeSurfaceFromWindowAsync(windowToken); } @Override - public void startProtoDump(byte[] bytes, int i, String s) throws RemoteException { + public void startProtoDump(byte[] bytes, int i, String s) { mInner.startProtoDump(bytes, i, s); } @Override - public boolean isImeTraceEnabled() throws RemoteException { + public boolean isImeTraceEnabled() { return mInner.isImeTraceEnabled(); } - @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) @Override - public void startImeTrace() throws RemoteException { + public void startImeTrace() { mInner.startImeTrace(); } - @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) + @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) @Override - public void stopImeTrace() throws RemoteException { + public void stopImeTrace() { mInner.stopImeTrace(); } @Override - public void startStylusHandwriting(IInputMethodClient client) - throws RemoteException { + public void startStylusHandwriting(IInputMethodClient client) { offload(() -> mInner.startStylusHandwriting(client)); } @@ -349,7 +343,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { public void startConnectionlessStylusHandwriting(IInputMethodClient client, int userId, @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, @Nullable String delegatorPackageName, - @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException { + @NonNull IConnectionlessHandwritingCallback callback) { offload(() -> mInner.startConnectionlessStylusHandwriting( client, userId, cursorAnchorInfo, delegatePackageName, delegatorPackageName, callback)); @@ -363,14 +357,11 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { @NonNull String delegatorPackageName, @InputMethodManager.HandwritingDelegateFlags int flags) { try { - return CompletableFuture.supplyAsync(() -> { - try { - return mInner.acceptStylusHandwritingDelegation( - client, userId, delegatePackageName, delegatorPackageName, flags); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - }, this::offload).get(); + return CompletableFuture.supplyAsync(() -> + mInner.acceptStylusHandwritingDelegation( + client, userId, delegatePackageName, delegatorPackageName, + flags), + this::offload).get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { @@ -384,8 +375,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { @UserIdInt int userId, @NonNull String delegatePackageName, @NonNull String delegatorPackageName, - @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) - throws RemoteException { + @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) { offload(() -> mInner.acceptStylusHandwritingDelegationAsync( client, userId, delegatePackageName, delegatorPackageName, flags, callback)); } @@ -401,52 +391,45 @@ public class ZeroJankProxy extends IInputMethodManager.Stub { } @Override - public boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless) - throws RemoteException { + public boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless) { return mInner.isStylusHandwritingAvailableAsUser(userId, connectionless); } - @EnforcePermission("android.permission.TEST_INPUT_METHOD") + @IInputMethodManagerImpl.PermissionVerified("android.permission.TEST_INPUT_METHOD") @Override - public void addVirtualStylusIdForTestSession(IInputMethodClient client) - throws RemoteException { + public void addVirtualStylusIdForTestSession(IInputMethodClient client) { mInner.addVirtualStylusIdForTestSession(client); } - @EnforcePermission("android.permission.TEST_INPUT_METHOD") + @IInputMethodManagerImpl.PermissionVerified("android.permission.TEST_INPUT_METHOD") @Override - public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) - throws RemoteException { + public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) { mInner.setStylusWindowIdleTimeoutForTest(client, timeout); } @Override - public IImeTracker getImeTrackerService() throws RemoteException { + public IImeTracker getImeTrackerService() { return mInner.getImeTrackerService(); } @BinderThread @Override public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, - @Nullable FileDescriptor err, - @NonNull String[] args, @Nullable ShellCallback callback, - @NonNull ResultReceiver resultReceiver) throws RemoteException { - ((InputMethodManagerService) mInner).onShellCommand( - in, out, err, args, callback, resultReceiver); + @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, + @NonNull ResultReceiver resultReceiver, @NonNull Binder self) { + mInner.onShellCommand(in, out, err, args, callback, resultReceiver, self); } @Override - protected void dump(@NonNull FileDescriptor fd, - @NonNull PrintWriter fout, + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args) { - ((InputMethodManagerService) mInner).dump(fd, fout, args); + mInner.dump(fd, fout, args); } private void sendOnStartInputResult( IInputMethodClient client, InputBindResult res, int startInputSeq) { synchronized (ImfLock.class) { - InputMethodManagerService service = (InputMethodManagerService) mInner; - final ClientState cs = service.getClientState(client); + final ClientState cs = mInner.getClientStateLocked(client); if (cs != null && cs.mClient != null) { cs.mClient.onStartInputResult(res, startInputSeq); } else { |