summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yohei Yukawa <yukawa@google.com> 2016-06-13 22:16:52 -0700
committer Yohei Yukawa <yukawa@google.com> 2016-06-14 21:01:41 +0000
commitccb024aa2b985ddc7f65b53191a84f1891f31cf2 (patch)
tree346df592527d7f56986c5adb0b231a05efa8f881
parent82f2df610894c6e423311467943a37330dbaa66b (diff)
Quick workaround for a performance regression in IME APIs.
It turns out that the performance of InputMethodManager#getCurrentInputMethodSubtype() is regressed from ~1ms to ~20ms when - Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE == -1 and - The active IME supports many subtypes (~100) because we try to find a fallback subtype based on the system locales every time when IMM#getCurrentInputMethodSubtype() is called. This could be contributing UI janks because spell checker clients running in the UI thread indirectly depend on that method. Fortunatelly the critical path is in InputMethodUtils#getImplicitlyApplicableSubtypesLockedImpl(), which is basically a state-less method. We can easily and safely cache its result by using LocaleList and InputMethod as cache keys. With this CL the performance basically recovers to the Android M level. Bug: 28889203 Change-Id: I5ed16c7f14cc18052854f4fd6c9bae8550c332ee
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java38
1 files changed, 38 insertions, 0 deletions
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index a028449e39d7..716997f815dc 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -41,6 +41,7 @@ import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -83,6 +84,17 @@ public class InputMethodUtils {
Locale.UK, // "en_GB"
};
+ // A temporary workaround for the performance concerns in
+ // #getImplicitlyApplicableSubtypesLocked(Resources, InputMethodInfo).
+ // TODO: Optimize all the critical paths including this one.
+ private static final Object sCacheLock = new Object();
+ @GuardedBy("sCacheLock")
+ private static LocaleList sCachedSystemLocales;
+ @GuardedBy("sCacheLock")
+ private static InputMethodInfo sCachedInputMethodInfo;
+ @GuardedBy("sCacheLock")
+ private static ArrayList<InputMethodSubtype> sCachedResult;
+
private InputMethodUtils() {
// This utility class is not publicly instantiable.
}
@@ -498,6 +510,32 @@ public class InputMethodUtils {
@VisibleForTesting
public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
Resources res, InputMethodInfo imi) {
+ final LocaleList systemLocales = res.getConfiguration().getLocales();
+
+ synchronized (sCacheLock) {
+ // We intentionally do not use InputMethodInfo#equals(InputMethodInfo) here because
+ // it does not check if subtypes are also identical.
+ if (systemLocales.equals(sCachedSystemLocales) && sCachedInputMethodInfo == imi) {
+ return new ArrayList<>(sCachedResult);
+ }
+ }
+
+ // Note: Only resource info in "res" is used in getImplicitlyApplicableSubtypesLockedImpl().
+ // TODO: Refactor getImplicitlyApplicableSubtypesLockedImpl() so that it can receive
+ // LocaleList rather than Resource.
+ final ArrayList<InputMethodSubtype> result =
+ getImplicitlyApplicableSubtypesLockedImpl(res, imi);
+ synchronized (sCacheLock) {
+ // Both LocaleList and InputMethodInfo are immutable. No need to copy them here.
+ sCachedSystemLocales = systemLocales;
+ sCachedInputMethodInfo = imi;
+ sCachedResult = new ArrayList<>(result);
+ }
+ return result;
+ }
+
+ private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLockedImpl(
+ Resources res, InputMethodInfo imi) {
final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
final LocaleList systemLocales = res.getConfiguration().getLocales();
final String systemLocale = systemLocales.get(0).toString();