From 4654609a7eacf2abe0d8f6cee7126763ecb81ad6 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Tue, 8 Mar 2022 10:34:19 -0800 Subject: [PATCH] Catch IllegalArgumentException from PackageManager in InputMethodUtils PackageManager APIs sometimes throw IllegalArgumentException. Failure to catch them in InputMethodManagerService may result in crash looping at an early boot stage. This CL makes sure that InputMethodUtils can gracefully catch IllegalArgumentException from PackageManagerService without causing crash of system_server. For normal situations, there should be no behavior change in this CL. Fix: 218385726 Test: Manually verified as follows. 1. Build aosp_coral-userdebug and flash it w/ wiping the user data. 2. Build coral-userdebug and flash it w/o wiping user the data. 3. Make sure that the device still boots. Change-Id: I58af03ec96103b60e20758558a92dd9408baab2f --- .../InputMethodManagerService.java | 28 ++++++++----- .../server/inputmethod/InputMethodUtils.java | 40 ++++++++++--------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 1f9d08063714f..77dcbd3e92773 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -1757,6 +1757,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } + @NonNull + private static PackageManager getPackageManagerForUser(@NonNull Context context, + @UserIdInt int userId) { + return context.getUserId() == userId + ? context.getPackageManager() + : context.createContextAsUser(UserHandle.of(userId), 0 /* flags */) + .getPackageManager(); + } + @GuardedBy("ImfLock.class") private void switchUserOnHandlerLocked(@UserIdInt int newUserId, IInputMethodClient clientToBeReset) { @@ -1801,9 +1810,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub updateFromSettingsLocked(true); if (initialUserSwitch) { - InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager, - mSettings.getEnabledInputMethodListLocked(), newUserId, - mContext.getBasePackageName()); + InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed( + getPackageManagerForUser(mContext, newUserId), + mSettings.getEnabledInputMethodListLocked()); } if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId @@ -1892,9 +1901,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId); buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */); updateFromSettingsLocked(true); - InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager, - mSettings.getEnabledInputMethodListLocked(), currentUserId, - mContext.getBasePackageName()); + InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed( + getPackageManagerForUser(mContext, currentUserId), + mSettings.getEnabledInputMethodListLocked()); } } } @@ -6122,10 +6131,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub setInputMethodEnabledLocked(imi.getId(), true); } updateInputMethodsFromSettingsLocked(true /* enabledMayChange */); - InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager, - mSettings.getEnabledInputMethodListLocked(), - mSettings.getCurrentUserId(), - mContext.getBasePackageName()); + InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed( + getPackageManagerForUser(mContext, mSettings.getCurrentUserId()), + mSettings.getEnabledInputMethodListLocked()); nextIme = mSettings.getSelectedInputMethod(); nextEnabledImes = mSettings.getEnabledInputMethodListLocked(); } else { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java index e619fff24d228..4633df23516d7 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java @@ -18,17 +18,16 @@ package com.android.server.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserHandleAware; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Build; import android.os.LocaleList; -import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -663,8 +662,9 @@ final class InputMethodUtils { return !subtype.isAuxiliary(); } - static void setNonSelectedSystemImesDisabledUntilUsed(IPackageManager packageManager, - List enabledImis, @UserIdInt int userId, String callingPackage) { + @UserHandleAware + static void setNonSelectedSystemImesDisabledUntilUsed(PackageManager packageManagerForUser, + List enabledImis) { if (DEBUG) { Slog.d(TAG, "setNonSelectedSystemImesDisabledUntilUsed"); } @@ -675,7 +675,8 @@ final class InputMethodUtils { } // Only the current spell checker should be treated as an enabled one. final SpellCheckerInfo currentSpellChecker = - TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(userId); + TextServicesManagerInternal.get().getCurrentSpellCheckerForUser( + packageManagerForUser.getUserId()); for (final String packageName : systemImesDisabledUntilUsed) { if (DEBUG) { Slog.d(TAG, "check " + packageName); @@ -702,11 +703,12 @@ final class InputMethodUtils { } ApplicationInfo ai = null; try { - ai = packageManager.getApplicationInfo(packageName, - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId); - } catch (RemoteException e) { + ai = packageManagerForUser.getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of( + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); + } catch (PackageManager.NameNotFoundException e) { Slog.w(TAG, "getApplicationInfo failed. packageName=" + packageName - + " userId=" + userId, e); + + " userId=" + packageManagerForUser.getUserId(), e); continue; } if (ai == null) { @@ -717,18 +719,18 @@ final class InputMethodUtils { if (!isSystemPackage) { continue; } - setDisabledUntilUsed(packageManager, packageName, userId, callingPackage); + setDisabledUntilUsed(packageManagerForUser, packageName); } } - private static void setDisabledUntilUsed(IPackageManager packageManager, String packageName, - int userId, String callingPackage) { + private static void setDisabledUntilUsed(PackageManager packageManagerForUser, + String packageName) { final int state; try { - state = packageManager.getApplicationEnabledSetting(packageName, userId); - } catch (RemoteException e) { + state = packageManagerForUser.getApplicationEnabledSetting(packageName); + } catch (IllegalArgumentException e) { Slog.w(TAG, "getApplicationEnabledSetting failed. packageName=" + packageName - + " userId=" + userId, e); + + " userId=" + packageManagerForUser.getUserId(), e); return; } if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT @@ -737,12 +739,12 @@ final class InputMethodUtils { Slog.d(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED"); } try { - packageManager.setApplicationEnabledSetting(packageName, + packageManagerForUser.setApplicationEnabledSetting(packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, - 0 /* newState */, userId, callingPackage); - } catch (RemoteException e) { + 0 /* newState */); + } catch (IllegalArgumentException e) { Slog.w(TAG, "setApplicationEnabledSetting failed. packageName=" + packageName - + " userId=" + userId + " callingPackage=" + callingPackage, e); + + " userId=" + packageManagerForUser.getUserId(), e); return; } } else {