diff options
| author | 2016-06-13 22:16:52 -0700 | |
|---|---|---|
| committer | 2016-06-14 21:01:41 +0000 | |
| commit | ccb024aa2b985ddc7f65b53191a84f1891f31cf2 (patch) | |
| tree | 346df592527d7f56986c5adb0b231a05efa8f881 | |
| parent | 82f2df610894c6e423311467943a37330dbaa66b (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.java | 38 |
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(); |