summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yohei Yukawa <yukawa@google.com> 2024-07-12 06:25:59 +0000
committer Yohei Yukawa <yukawa@google.com> 2024-07-12 06:25:59 +0000
commitcf9acd883eac083e1a5cbbaba096847271c30ae4 (patch)
tree413d9549e3517ff677a738f1a5acb48cb25cbbe3
parent05b5e0e29ec54feed2c02edf7a62ea3fe6a4e2e9 (diff)
Remove remaining UserLifecycleListener deps from IMMS utils
With this CL, the dependency on UserLifecycleListener will be fully migrated into InputMethodManagerService.Lifecycle so that future readers can find various user-related callbacks in one place. The observable semantics should remain unchanged. Fix: 352354308 Test: presubmit Test: atest FrameworksInputMethodSystemServerTests Flag: EXEMPT refactor Change-Id: I337fb084a9395eed7422d6889bf4f15d583c769c
-rw-r--r--services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java51
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java46
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java40
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);
+ }
}
}