Loading services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java +4 −47 Original line number Diff line number Diff line Loading @@ -18,20 +18,14 @@ package com.android.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.os.Process; import android.util.IntArray; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import java.util.ArrayList; import java.util.concurrent.locks.Condition; Loading Loading @@ -225,37 +219,8 @@ final class AdditionalSubtypeMapRepository { sWriter.startThread(); } static void initialize(@NonNull Handler ioHandler, @NonNull Context context) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); ioHandler.post(() -> { userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserCreated(UserInfo user, @Nullable Object token) { final int userId = user.id; sWriter.onUserCreated(userId); ioHandler.post(() -> { synchronized (ImfLock.class) { if (!sPerUserMap.contains(userId)) { final AdditionalSubtypeMap additionalSubtypeMap = AdditionalSubtypeUtils.load(userId); sPerUserMap.put(userId, additionalSubtypeMap); final InputMethodSettings settings = InputMethodManagerService .queryInputMethodServicesInternal(context, userId, additionalSubtypeMap, DirectBootAwareness.AUTO); InputMethodSettingsRepository.put(userId, settings); } } }); } @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; @AnyThread static void remove(@UserIdInt int userId, @NonNull Handler ioHandler) { sWriter.onUserRemoved(userId); ioHandler.post(() -> { synchronized (ImfLock.class) { Loading @@ -263,12 +228,4 @@ final class AdditionalSubtypeMapRepository { } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { sPerUserMap.put(userId, AdditionalSubtypeUtils.load(userId)); } } }); } } services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +36 −10 Original line number Diff line number Diff line Loading @@ -933,6 +933,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // For production code, hook up user lifecycle mService.mUserManagerInternal.addUserLifecycleListener(this); // Also schedule user init tasks onto an I/O thread. initializeUsersAsync(context, mService.mIoHandler, mService.mUserManagerInternal.getUserIds()); } @VisibleForTesting Loading Loading @@ -1015,6 +1019,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @Override public void onUserCreated(UserInfo user, @Nullable Object token) { // Called directly from UserManagerService. Do not block the calling thread. initializeUsersAsync(mService.mContext, mService.mIoHandler, new int[user.id]); } @Override Loading @@ -1022,6 +1027,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // Called directly from UserManagerService. Do not block the calling thread. final int userId = user.id; SecureSettingsWrapper.onUserRemoved(userId); AdditionalSubtypeMapRepository.remove(userId, mService.mIoHandler); InputMethodSettingsRepository.remove(userId); mService.mUserDataRepository.remove(userId); } Loading Loading @@ -1049,6 +1056,35 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. }); } @AnyThread private static void initializeUsersAsync( @NonNull Context context, @NonNull Handler ioHandler, @UserIdInt int[] userIds) { ioHandler.post(() -> { // We first create InputMethodMap for each user without loading AdditionalSubtypes. final int numUsers = userIds.length; final InputMethodMap[] rawMethodMaps = new InputMethodMap[numUsers]; for (int i = 0; i < numUsers; ++i) { final int userId = userIds[i]; rawMethodMaps[i] = InputMethodManagerService.queryInputMethodServicesInternal( context, userId, AdditionalSubtypeMap.EMPTY_MAP, DirectBootAwareness.AUTO).getMethodMap(); } // Then create full InputMethodMap for each user. Note that // AdditionalSubtypeMapRepository#get() and InputMethodSettingsRepository#put() // need to be called with ImfLock held (b/352387655). // TODO(b/343601565): Avoid ImfLock after fixing b/352387655. synchronized (ImfLock.class) { for (int i = 0; i < numUsers; ++i) { final int userId = userIds[i]; final var map = AdditionalSubtypeMapRepository.get(userId); final var methodMap = rawMethodMaps[i].applyAdditionalSubtypes(map); final var settings = InputMethodSettings.create(methodMap, userId); InputMethodSettingsRepository.put(userId, settings); } } }); } } void onUnlockUser(@UserIdInt int userId) { Loading Loading @@ -1121,16 +1157,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mShowOngoingImeSwitcherForPhones = false; // Executing InputMethodSettingsRepository.initialize() does not mean that it // immediately becomes ready to return the up-to-date InputMethodSettings for each // running user, because we want to return from the constructor as early as possible so // as not to delay the system boot process. // Search for InputMethodSettingsRepository.put() to find where and when it's actually // being updated. In general IMMS should refrain from exposing the existence of IMEs // until systemReady(). InputMethodSettingsRepository.initialize(mIoHandler, mContext); AdditionalSubtypeMapRepository.initialize(mIoHandler, mContext); mCurrentUserId = mActivityManagerInternal.getCurrentUserId(); @SuppressWarnings("GuardedBy") final IntFunction<InputMethodBindingController> bindingControllerFactory = userId -> new InputMethodBindingController(userId, Loading services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java +6 −34 Original line number Diff line number Diff line Loading @@ -16,17 +16,12 @@ package com.android.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; final class InputMethodSettingsRepository { @GuardedBy("ImfLock.class") Loading Loading @@ -54,33 +49,10 @@ final class InputMethodSettingsRepository { sPerUserMap.put(userId, obj); } static void initialize(@NonNull Handler ioHandler, @NonNull Context context) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); ioHandler.post(() -> { userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; ioHandler.post(() -> { @AnyThread static void remove(@UserIdInt int userId) { synchronized (ImfLock.class) { sPerUserMap.remove(userId); } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { final InputMethodSettings settings = InputMethodManagerService.queryInputMethodServicesInternal( context, userId, AdditionalSubtypeMapRepository.get(userId), DirectBootAwareness.AUTO); put(userId, settings); } } }); } } Loading
services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java +4 −47 Original line number Diff line number Diff line Loading @@ -18,20 +18,14 @@ package com.android.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.os.Process; import android.util.IntArray; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import java.util.ArrayList; import java.util.concurrent.locks.Condition; Loading Loading @@ -225,37 +219,8 @@ final class AdditionalSubtypeMapRepository { sWriter.startThread(); } static void initialize(@NonNull Handler ioHandler, @NonNull Context context) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); ioHandler.post(() -> { userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserCreated(UserInfo user, @Nullable Object token) { final int userId = user.id; sWriter.onUserCreated(userId); ioHandler.post(() -> { synchronized (ImfLock.class) { if (!sPerUserMap.contains(userId)) { final AdditionalSubtypeMap additionalSubtypeMap = AdditionalSubtypeUtils.load(userId); sPerUserMap.put(userId, additionalSubtypeMap); final InputMethodSettings settings = InputMethodManagerService .queryInputMethodServicesInternal(context, userId, additionalSubtypeMap, DirectBootAwareness.AUTO); InputMethodSettingsRepository.put(userId, settings); } } }); } @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; @AnyThread static void remove(@UserIdInt int userId, @NonNull Handler ioHandler) { sWriter.onUserRemoved(userId); ioHandler.post(() -> { synchronized (ImfLock.class) { Loading @@ -263,12 +228,4 @@ final class AdditionalSubtypeMapRepository { } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { sPerUserMap.put(userId, AdditionalSubtypeUtils.load(userId)); } } }); } }
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +36 −10 Original line number Diff line number Diff line Loading @@ -933,6 +933,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // For production code, hook up user lifecycle mService.mUserManagerInternal.addUserLifecycleListener(this); // Also schedule user init tasks onto an I/O thread. initializeUsersAsync(context, mService.mIoHandler, mService.mUserManagerInternal.getUserIds()); } @VisibleForTesting Loading Loading @@ -1015,6 +1019,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @Override public void onUserCreated(UserInfo user, @Nullable Object token) { // Called directly from UserManagerService. Do not block the calling thread. initializeUsersAsync(mService.mContext, mService.mIoHandler, new int[user.id]); } @Override Loading @@ -1022,6 +1027,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // Called directly from UserManagerService. Do not block the calling thread. final int userId = user.id; SecureSettingsWrapper.onUserRemoved(userId); AdditionalSubtypeMapRepository.remove(userId, mService.mIoHandler); InputMethodSettingsRepository.remove(userId); mService.mUserDataRepository.remove(userId); } Loading Loading @@ -1049,6 +1056,35 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. }); } @AnyThread private static void initializeUsersAsync( @NonNull Context context, @NonNull Handler ioHandler, @UserIdInt int[] userIds) { ioHandler.post(() -> { // We first create InputMethodMap for each user without loading AdditionalSubtypes. final int numUsers = userIds.length; final InputMethodMap[] rawMethodMaps = new InputMethodMap[numUsers]; for (int i = 0; i < numUsers; ++i) { final int userId = userIds[i]; rawMethodMaps[i] = InputMethodManagerService.queryInputMethodServicesInternal( context, userId, AdditionalSubtypeMap.EMPTY_MAP, DirectBootAwareness.AUTO).getMethodMap(); } // Then create full InputMethodMap for each user. Note that // AdditionalSubtypeMapRepository#get() and InputMethodSettingsRepository#put() // need to be called with ImfLock held (b/352387655). // TODO(b/343601565): Avoid ImfLock after fixing b/352387655. synchronized (ImfLock.class) { for (int i = 0; i < numUsers; ++i) { final int userId = userIds[i]; final var map = AdditionalSubtypeMapRepository.get(userId); final var methodMap = rawMethodMaps[i].applyAdditionalSubtypes(map); final var settings = InputMethodSettings.create(methodMap, userId); InputMethodSettingsRepository.put(userId, settings); } } }); } } void onUnlockUser(@UserIdInt int userId) { Loading Loading @@ -1121,16 +1157,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mShowOngoingImeSwitcherForPhones = false; // Executing InputMethodSettingsRepository.initialize() does not mean that it // immediately becomes ready to return the up-to-date InputMethodSettings for each // running user, because we want to return from the constructor as early as possible so // as not to delay the system boot process. // Search for InputMethodSettingsRepository.put() to find where and when it's actually // being updated. In general IMMS should refrain from exposing the existence of IMEs // until systemReady(). InputMethodSettingsRepository.initialize(mIoHandler, mContext); AdditionalSubtypeMapRepository.initialize(mIoHandler, mContext); mCurrentUserId = mActivityManagerInternal.getCurrentUserId(); @SuppressWarnings("GuardedBy") final IntFunction<InputMethodBindingController> bindingControllerFactory = userId -> new InputMethodBindingController(userId, Loading
services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java +6 −34 Original line number Diff line number Diff line Loading @@ -16,17 +16,12 @@ package com.android.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.DirectBootAwareness; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; final class InputMethodSettingsRepository { @GuardedBy("ImfLock.class") Loading Loading @@ -54,33 +49,10 @@ final class InputMethodSettingsRepository { sPerUserMap.put(userId, obj); } static void initialize(@NonNull Handler ioHandler, @NonNull Context context) { final UserManagerInternal userManagerInternal = LocalServices.getService(UserManagerInternal.class); ioHandler.post(() -> { userManagerInternal.addUserLifecycleListener( new UserManagerInternal.UserLifecycleListener() { @Override public void onUserRemoved(UserInfo user) { final int userId = user.id; ioHandler.post(() -> { @AnyThread static void remove(@UserIdInt int userId) { synchronized (ImfLock.class) { sPerUserMap.remove(userId); } }); } }); synchronized (ImfLock.class) { for (int userId : userManagerInternal.getUserIds()) { final InputMethodSettings settings = InputMethodManagerService.queryInputMethodServicesInternal( context, userId, AdditionalSubtypeMapRepository.get(userId), DirectBootAwareness.AUTO); put(userId, settings); } } }); } }