diff options
3 files changed, 46 insertions, 91 deletions
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java index 91ab8720ac0b..996859027e91 100644 --- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java +++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java @@ -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; @@ -225,49 +219,12 @@ final class AdditionalSubtypeMapRepository { sWriter.startThread(); } - static void initialize(@NonNull Handler ioHandler, @NonNull Context context) { - final UserManagerInternal userManagerInternal = - LocalServices.getService(UserManagerInternal.class); + @AnyThread + static void remove(@UserIdInt int userId, @NonNull Handler ioHandler) { + sWriter.onUserRemoved(userId); 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; - sWriter.onUserRemoved(userId); - ioHandler.post(() -> { - synchronized (ImfLock.class) { - sPerUserMap.remove(userId); - } - }); - } - }); synchronized (ImfLock.class) { - for (int userId : userManagerInternal.getUserIds()) { - sPerUserMap.put(userId, AdditionalSubtypeUtils.load(userId)); - } + sPerUserMap.remove(userId); } }); } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 7daf9582cdd6..e1803dc7caf6 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -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 @@ -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 @@ -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); } @@ -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) { @@ -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, diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java index a4d8ee566755..50ba36450bda 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java @@ -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") @@ -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(() -> { - 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); - } - } - }); + @AnyThread + static void remove(@UserIdInt int userId) { + synchronized (ImfLock.class) { + sPerUserMap.remove(userId); + } } } |