Loading services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +3 −23 Original line number Diff line number Diff line Loading @@ -74,7 +74,6 @@ final class InputMethodBindingController { @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private boolean mVisibleBound; @GuardedBy("ImfLock.class") private boolean mSupportsStylusHw; @GuardedBy("ImfLock.class") private boolean mSupportsConnectionlessStylusHw; Loading Loading @@ -194,27 +193,6 @@ final class InputMethodBindingController { return mCurIntent; } /** * The current binding sequence number, incremented every time there is * a new bind performed. */ @GuardedBy("ImfLock.class") int getSequenceNumber() { return mCurSeq; } /** * Increase the current binding sequence number by one. * Reset to 1 on overflow. */ @GuardedBy("ImfLock.class") void advanceSequenceNumber() { mCurSeq += 1; if (mCurSeq <= 0) { mCurSeq = 1; } } /** * If non-null, this is the input method service we are currently connected * to. Loading Loading @@ -435,9 +413,11 @@ final class InputMethodBindingController { mLastBindTime = SystemClock.uptimeMillis(); addFreshWindowToken(); final UserData monitor = UserData.getOrCreate( mService.getCurrentImeUserIdLocked()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, null, mCurId, mCurSeq, false); null, null, null, mCurId, monitor.mSequence.getSequenceNumber(), false); } Slog.w(InputMethodManagerService.TAG, Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +5 −2 Original line number Diff line number Diff line Loading @@ -479,7 +479,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ @GuardedBy("ImfLock.class") private int getSequenceNumberLocked() { return mBindingController.getSequenceNumber(); final UserData monitor = UserData.getOrCreate(mCurrentUserId); return monitor.mSequence.getSequenceNumber(); } /** Loading @@ -488,7 +489,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ @GuardedBy("ImfLock.class") private void advanceSequenceNumberLocked() { mBindingController.advanceSequenceNumber(); final UserData monitor = UserData.getOrCreate(mCurrentUserId); monitor.mSequence.advanceSequenceNumber(); } @GuardedBy("ImfLock.class") Loading Loading @@ -1369,6 +1371,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // InputMethodSettingsRepository should be initialized before buildInputMethodListLocked InputMethodSettingsRepository.initialize(mHandler, mContext); AdditionalSubtypeMapRepository.initialize(mHandler, mContext); UserData.initialize(mHandler); mCurrentUserId = mActivityManagerInternal.getCurrentUserId(); Loading services/core/java/com/android/server/inputmethod/Sequence.java 0 → 100644 +45 −0 Original line number Diff line number Diff line /* * 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 com.android.internal.annotations.GuardedBy; /** * A sequence number utility class that only generate positive numbers. */ final class Sequence { private final Object mLock = new Object(); private int mSequence; int getSequenceNumber() { synchronized (mLock) { return mSequence; } } @GuardedBy("ImfLock.class") void advanceSequenceNumber() { synchronized (mLock) { mSequence++; if (mSequence <= 0) { mSequence = 1; } } } } services/core/java/com/android/server/inputmethod/UserData.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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 android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.UserInfo; import android.os.Handler; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; final class UserData { @NonNull private static final SparseArray<UserData> sPerUserMonitor = new SparseArray<>(); @UserIdInt final int mUserId; @GuardedBy("ImfLock.class") final Sequence mSequence = new Sequence(); /** * Not intended to be instantiated. */ private UserData(int userId) { mUserId = userId; } @GuardedBy("ImfLock.class") static UserData getOrCreate(@UserIdInt int userId) { UserData monitor = sPerUserMonitor.get(userId); if (monitor == null) { monitor = new UserData(userId); sPerUserMonitor.put(userId, monitor); } return monitor; } static void initialize(Handler handler) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; handler.post(() -> { synchronized (ImfLock.class) { sPerUserMonitor.remove(userId); } }); } @Override public void onUserCreated(UserInfo user, Object unusedToken) { final int userId = user.id; handler.post(() -> { synchronized (ImfLock.class) { getOrCreate(userId); } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { getOrCreate(userId); } } } } Loading
services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +3 −23 Original line number Diff line number Diff line Loading @@ -74,7 +74,6 @@ final class InputMethodBindingController { @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod; @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID; @GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken; @GuardedBy("ImfLock.class") private int mCurSeq; @GuardedBy("ImfLock.class") private boolean mVisibleBound; @GuardedBy("ImfLock.class") private boolean mSupportsStylusHw; @GuardedBy("ImfLock.class") private boolean mSupportsConnectionlessStylusHw; Loading Loading @@ -194,27 +193,6 @@ final class InputMethodBindingController { return mCurIntent; } /** * The current binding sequence number, incremented every time there is * a new bind performed. */ @GuardedBy("ImfLock.class") int getSequenceNumber() { return mCurSeq; } /** * Increase the current binding sequence number by one. * Reset to 1 on overflow. */ @GuardedBy("ImfLock.class") void advanceSequenceNumber() { mCurSeq += 1; if (mCurSeq <= 0) { mCurSeq = 1; } } /** * If non-null, this is the input method service we are currently connected * to. Loading Loading @@ -435,9 +413,11 @@ final class InputMethodBindingController { mLastBindTime = SystemClock.uptimeMillis(); addFreshWindowToken(); final UserData monitor = UserData.getOrCreate( mService.getCurrentImeUserIdLocked()); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, null, null, null, mCurId, mCurSeq, false); null, null, null, mCurId, monitor.mSequence.getSequenceNumber(), false); } Slog.w(InputMethodManagerService.TAG, Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +5 −2 Original line number Diff line number Diff line Loading @@ -479,7 +479,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ @GuardedBy("ImfLock.class") private int getSequenceNumberLocked() { return mBindingController.getSequenceNumber(); final UserData monitor = UserData.getOrCreate(mCurrentUserId); return monitor.mSequence.getSequenceNumber(); } /** Loading @@ -488,7 +489,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ @GuardedBy("ImfLock.class") private void advanceSequenceNumberLocked() { mBindingController.advanceSequenceNumber(); final UserData monitor = UserData.getOrCreate(mCurrentUserId); monitor.mSequence.advanceSequenceNumber(); } @GuardedBy("ImfLock.class") Loading Loading @@ -1369,6 +1371,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // InputMethodSettingsRepository should be initialized before buildInputMethodListLocked InputMethodSettingsRepository.initialize(mHandler, mContext); AdditionalSubtypeMapRepository.initialize(mHandler, mContext); UserData.initialize(mHandler); mCurrentUserId = mActivityManagerInternal.getCurrentUserId(); Loading
services/core/java/com/android/server/inputmethod/Sequence.java 0 → 100644 +45 −0 Original line number Diff line number Diff line /* * 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 com.android.internal.annotations.GuardedBy; /** * A sequence number utility class that only generate positive numbers. */ final class Sequence { private final Object mLock = new Object(); private int mSequence; int getSequenceNumber() { synchronized (mLock) { return mSequence; } } @GuardedBy("ImfLock.class") void advanceSequenceNumber() { synchronized (mLock) { mSequence++; if (mSequence <= 0) { mSequence = 1; } } } }
services/core/java/com/android/server/inputmethod/UserData.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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 android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.UserInfo; import android.os.Handler; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; final class UserData { @NonNull private static final SparseArray<UserData> sPerUserMonitor = new SparseArray<>(); @UserIdInt final int mUserId; @GuardedBy("ImfLock.class") final Sequence mSequence = new Sequence(); /** * Not intended to be instantiated. */ private UserData(int userId) { mUserId = userId; } @GuardedBy("ImfLock.class") static UserData getOrCreate(@UserIdInt int userId) { UserData monitor = sPerUserMonitor.get(userId); if (monitor == null) { monitor = new UserData(userId); sPerUserMonitor.put(userId, monitor); } return monitor; } static void initialize(Handler handler) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; handler.post(() -> { synchronized (ImfLock.class) { sPerUserMonitor.remove(userId); } }); } @Override public void onUserCreated(UserInfo user, Object unusedToken) { final int userId = user.id; handler.post(() -> { synchronized (ImfLock.class) { getOrCreate(userId); } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { getOrCreate(userId); } } } }