Loading services/core/java/com/android/server/am/AppErrors.java +51 −11 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Message; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; Loading @@ -63,6 +64,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.server.LocalServices; import com.android.server.PackageWatchdog; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; import com.android.server.usage.AppStandbyInternal; import com.android.server.wm.WindowProcessController; Loading Loading @@ -868,9 +871,6 @@ class AppErrors { private boolean handleAppCrashLSPB(ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { final long now = SystemClock.uptimeMillis(); final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; Long crashTime; Long crashTimePersistent; Loading @@ -881,6 +881,8 @@ class AppErrors { final boolean persistent = app.isPersistent(); final WindowProcessController proc = app.getWindowProcessController(); final ProcessErrorStateRecord errState = app.mErrorState; final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, getVisibleUserId(userId)) != 0; if (!app.isolated) { crashTime = mProcessCrashTimes.get(processName, uid); Loading Loading @@ -1000,9 +1002,6 @@ class AppErrors { void handleShowAppErrorUi(Message msg) { AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj; boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; final int userId; synchronized (mProcLock) { Loading @@ -1027,7 +1026,11 @@ class AppErrors { for (int profileId : mService.mUserController.getCurrentProfileIds()) { isBackground &= (userId != profileId); } if (isBackground && !showBackground) { int visibleUserId = getVisibleUserId(userId); boolean isVisibleUser = isVisibleBackgroundUser(visibleUserId); boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, visibleUserId) != 0; if (isBackground && !showBackground && !isVisibleUser) { Slog.w(TAG, "Skipping crash dialog of " + proc + ": background"); if (res != null) { res.set(AppErrorDialog.BACKGROUND_USER); Loading @@ -1054,7 +1057,7 @@ class AppErrors { final long now = SystemClock.uptimeMillis(); final boolean shouldThottle = crashShowErrorTime != null && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL; if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground) if ((mService.mAtmInternal.canShowErrorDialogs(visibleUserId) || showBackground) && !crashSilenced && !shouldThottle && (showFirstCrash || showFirstCrashDevOption || data.repeating)) { Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId); Loading Loading @@ -1103,10 +1106,10 @@ class AppErrors { return; } int visibleUserId = getVisibleUserId(proc.userId); boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { Settings.Secure.ANR_SHOW_BACKGROUND, 0, visibleUserId) != 0; if (mService.mAtmInternal.canShowErrorDialogs(visibleUserId) || showBackground) { AnrController anrController = errState.getDialogController().getAnrController(); if (anrController == null) { errState.getDialogController().showAnrDialogs(data); Loading Loading @@ -1162,6 +1165,43 @@ class AppErrors { } } /** * Returns the user ID of the visible user associated with the error occurrence. * * <p>For most cases it will return the current foreground user ID, but on devices that * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, * it will return the given app user ID passed as parameter. * * @param appUserId The user ID of the app where the error occurred. * @return The ID of the visible user associated with the error. */ private int getVisibleUserId(int appUserId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return mService.mUserController.getCurrentUserId(); } return appUserId; } /** * Checks if the given user is a visible background user, which is a full, background user * assigned to secondary displays on the devices that have * {@link UserManager#isVisibleBackgroundUsersEnabled() * config_multiuserVisibleBackgroundUsers enabled} (for example, passenger users on * automotive builds, using the display associated with their seats). * * @see UserManager#isUserVisible() */ private boolean isVisibleBackgroundUser(int userId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return false; } boolean isForeground = mService.mUserController.getCurrentUserId() == userId; boolean isProfile = UserManagerService.getInstance().isProfile(userId); boolean isVisible = LocalServices.getService(UserManagerInternal.class) .isUserVisible(userId); return isVisible && !isForeground && !isProfile; } /** * Information about a process that is currently marked as bad. */ Loading services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -584,7 +584,7 @@ public abstract class ActivityTaskManagerInternal { public abstract void clearLockedTasks(String reason); public abstract void updateUserConfiguration(); public abstract boolean canShowErrorDialogs(); public abstract boolean canShowErrorDialogs(int userId); public abstract void setProfileApp(String profileApp); public abstract void setProfileProc(WindowProcessController wpc); Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +68 −8 Original line number Diff line number Diff line Loading @@ -190,6 +190,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -4899,14 +4900,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * dialog / global actions also might want different behaviors. */ private void updateShouldShowDialogsLocked(Configuration config) { mShowDialogs = shouldShowDialogs(config, /* checkUiMode= */ true); } private boolean shouldShowDialogs(Configuration config, boolean checkUiMode) { final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH && config.navigation == Configuration.NAVIGATION_NONAV); final boolean hideDialogsSet = Settings.Global.getInt(mContext.getContentResolver(), HIDE_ERROR_DIALOGS, 0) != 0; mShowDialogs = inputMethodExists && ActivityTaskManager.currentUiModeSupportsErrorDialogs(config) && !hideDialogsSet; boolean showDialogs = inputMethodExists && !hideDialogsSet; if (checkUiMode) { showDialogs = showDialogs && ActivityTaskManager.currentUiModeSupportsErrorDialogs(config); } return showDialogs; } private void updateFontScaleIfNeeded(@UserIdInt int userId) { Loading Loading @@ -7148,15 +7156,67 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override public boolean canShowErrorDialogs() { public boolean canShowErrorDialogs(int userId) { synchronized (mGlobalLock) { return mShowDialogs && !mSleeping && !mShuttingDown final boolean showDialogs = mShowDialogs || shouldShowDialogsForVisibleBackgroundUserLocked(userId); final UserInfo userInfo = getUserManager().getUserInfo(userId); if (userInfo == null) { // Unable to retrieve user information. Returning false, assuming there is // no valid user with the given id. return false; } return showDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY) && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, mAmInternal.getCurrentUserId()) && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, userId) && !(UserManager.isDeviceInDemoMode(mContext) && mAmInternal.getCurrentUser().isDemo()); && userInfo.isDemo()); } } /** * Checks if the given user is a visible background user, which is a full, background user * assigned to secondary displays on the devices that have * {@link UserManager#isVisibleBackgroundUsersEnabled() * config_multiuserVisibleBackgroundUsers enabled} (for example, passenger users on * automotive builds, using the display associated with their seats). * * @see UserManager#isUserVisible() */ private boolean isVisibleBackgroundUser(int userId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return false; } boolean isForeground = getCurrentUserId() == userId; boolean isProfile = getUserManager().isProfile(userId); boolean isVisible = mWindowManager.mUmInternal.isUserVisible(userId); return isVisible && !isForeground && !isProfile; } /** * In a car environment, {@link ActivityTaskManagerService#mShowDialogs} is always set to * {@code false} from {@link ActivityTaskManagerService#updateShouldShowDialogsLocked} * because its UI mode is {@link Configuration#UI_MODE_TYPE_CAR}. Thus, error dialogs are * not displayed when an ANR or a crash occurs. However, in the automotive multi-user * multi-display environment, this can confuse the passenger users and leave them * uninformed when an app is terminated by the ANR or crash without any notification. * To address this, error dialogs are allowed for the passenger users who have UI access * on assigned displays (a.k.a. visible background users) on devices that have * config_multiuserVisibleBackgroundUsers enabled even though the UI mode is * {@link Configuration#UI_MODE_TYPE_CAR}. * * @see ActivityTaskManagerService#updateShouldShowDialogsLocked */ private boolean shouldShowDialogsForVisibleBackgroundUserLocked(int userId) { if (!isVisibleBackgroundUser(userId)) { return false; } final int displayId = mWindowManager.mUmInternal.getMainDisplayAssignedToUser(userId); final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId); if (dc == null) { return false; } return shouldShowDialogs(dc.getConfiguration(), /* checkUiMode= */ false); } @Override Loading Loading
services/core/java/com/android/server/am/AppErrors.java +51 −11 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Message; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; Loading @@ -63,6 +64,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.server.LocalServices; import com.android.server.PackageWatchdog; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; import com.android.server.usage.AppStandbyInternal; import com.android.server.wm.WindowProcessController; Loading Loading @@ -868,9 +871,6 @@ class AppErrors { private boolean handleAppCrashLSPB(ProcessRecord app, String reason, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { final long now = SystemClock.uptimeMillis(); final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; Long crashTime; Long crashTimePersistent; Loading @@ -881,6 +881,8 @@ class AppErrors { final boolean persistent = app.isPersistent(); final WindowProcessController proc = app.getWindowProcessController(); final ProcessErrorStateRecord errState = app.mErrorState; final boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, getVisibleUserId(userId)) != 0; if (!app.isolated) { crashTime = mProcessCrashTimes.get(processName, uid); Loading Loading @@ -1000,9 +1002,6 @@ class AppErrors { void handleShowAppErrorUi(Message msg) { AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj; boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; final int userId; synchronized (mProcLock) { Loading @@ -1027,7 +1026,11 @@ class AppErrors { for (int profileId : mService.mUserController.getCurrentProfileIds()) { isBackground &= (userId != profileId); } if (isBackground && !showBackground) { int visibleUserId = getVisibleUserId(userId); boolean isVisibleUser = isVisibleBackgroundUser(visibleUserId); boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, visibleUserId) != 0; if (isBackground && !showBackground && !isVisibleUser) { Slog.w(TAG, "Skipping crash dialog of " + proc + ": background"); if (res != null) { res.set(AppErrorDialog.BACKGROUND_USER); Loading @@ -1054,7 +1057,7 @@ class AppErrors { final long now = SystemClock.uptimeMillis(); final boolean shouldThottle = crashShowErrorTime != null && now < crashShowErrorTime + ActivityManagerConstants.MIN_CRASH_INTERVAL; if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground) if ((mService.mAtmInternal.canShowErrorDialogs(visibleUserId) || showBackground) && !crashSilenced && !shouldThottle && (showFirstCrash || showFirstCrashDevOption || data.repeating)) { Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId); Loading Loading @@ -1103,10 +1106,10 @@ class AppErrors { return; } int visibleUserId = getVisibleUserId(proc.userId); boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0, mService.mUserController.getCurrentUserId()) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { Settings.Secure.ANR_SHOW_BACKGROUND, 0, visibleUserId) != 0; if (mService.mAtmInternal.canShowErrorDialogs(visibleUserId) || showBackground) { AnrController anrController = errState.getDialogController().getAnrController(); if (anrController == null) { errState.getDialogController().showAnrDialogs(data); Loading Loading @@ -1162,6 +1165,43 @@ class AppErrors { } } /** * Returns the user ID of the visible user associated with the error occurrence. * * <p>For most cases it will return the current foreground user ID, but on devices that * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, * it will return the given app user ID passed as parameter. * * @param appUserId The user ID of the app where the error occurred. * @return The ID of the visible user associated with the error. */ private int getVisibleUserId(int appUserId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return mService.mUserController.getCurrentUserId(); } return appUserId; } /** * Checks if the given user is a visible background user, which is a full, background user * assigned to secondary displays on the devices that have * {@link UserManager#isVisibleBackgroundUsersEnabled() * config_multiuserVisibleBackgroundUsers enabled} (for example, passenger users on * automotive builds, using the display associated with their seats). * * @see UserManager#isUserVisible() */ private boolean isVisibleBackgroundUser(int userId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return false; } boolean isForeground = mService.mUserController.getCurrentUserId() == userId; boolean isProfile = UserManagerService.getInstance().isProfile(userId); boolean isVisible = LocalServices.getService(UserManagerInternal.class) .isUserVisible(userId); return isVisible && !isForeground && !isProfile; } /** * Information about a process that is currently marked as bad. */ Loading
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -584,7 +584,7 @@ public abstract class ActivityTaskManagerInternal { public abstract void clearLockedTasks(String reason); public abstract void updateUserConfiguration(); public abstract boolean canShowErrorDialogs(); public abstract boolean canShowErrorDialogs(int userId); public abstract void setProfileApp(String profileApp); public abstract void setProfileProc(WindowProcessController wpc); Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +68 −8 Original line number Diff line number Diff line Loading @@ -190,6 +190,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; Loading Loading @@ -4899,14 +4900,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { * dialog / global actions also might want different behaviors. */ private void updateShouldShowDialogsLocked(Configuration config) { mShowDialogs = shouldShowDialogs(config, /* checkUiMode= */ true); } private boolean shouldShowDialogs(Configuration config, boolean checkUiMode) { final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH && config.navigation == Configuration.NAVIGATION_NONAV); final boolean hideDialogsSet = Settings.Global.getInt(mContext.getContentResolver(), HIDE_ERROR_DIALOGS, 0) != 0; mShowDialogs = inputMethodExists && ActivityTaskManager.currentUiModeSupportsErrorDialogs(config) && !hideDialogsSet; boolean showDialogs = inputMethodExists && !hideDialogsSet; if (checkUiMode) { showDialogs = showDialogs && ActivityTaskManager.currentUiModeSupportsErrorDialogs(config); } return showDialogs; } private void updateFontScaleIfNeeded(@UserIdInt int userId) { Loading Loading @@ -7148,15 +7156,67 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override public boolean canShowErrorDialogs() { public boolean canShowErrorDialogs(int userId) { synchronized (mGlobalLock) { return mShowDialogs && !mSleeping && !mShuttingDown final boolean showDialogs = mShowDialogs || shouldShowDialogsForVisibleBackgroundUserLocked(userId); final UserInfo userInfo = getUserManager().getUserInfo(userId); if (userInfo == null) { // Unable to retrieve user information. Returning false, assuming there is // no valid user with the given id. return false; } return showDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY) && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, mAmInternal.getCurrentUserId()) && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, userId) && !(UserManager.isDeviceInDemoMode(mContext) && mAmInternal.getCurrentUser().isDemo()); && userInfo.isDemo()); } } /** * Checks if the given user is a visible background user, which is a full, background user * assigned to secondary displays on the devices that have * {@link UserManager#isVisibleBackgroundUsersEnabled() * config_multiuserVisibleBackgroundUsers enabled} (for example, passenger users on * automotive builds, using the display associated with their seats). * * @see UserManager#isUserVisible() */ private boolean isVisibleBackgroundUser(int userId) { if (!UserManager.isVisibleBackgroundUsersEnabled()) { return false; } boolean isForeground = getCurrentUserId() == userId; boolean isProfile = getUserManager().isProfile(userId); boolean isVisible = mWindowManager.mUmInternal.isUserVisible(userId); return isVisible && !isForeground && !isProfile; } /** * In a car environment, {@link ActivityTaskManagerService#mShowDialogs} is always set to * {@code false} from {@link ActivityTaskManagerService#updateShouldShowDialogsLocked} * because its UI mode is {@link Configuration#UI_MODE_TYPE_CAR}. Thus, error dialogs are * not displayed when an ANR or a crash occurs. However, in the automotive multi-user * multi-display environment, this can confuse the passenger users and leave them * uninformed when an app is terminated by the ANR or crash without any notification. * To address this, error dialogs are allowed for the passenger users who have UI access * on assigned displays (a.k.a. visible background users) on devices that have * config_multiuserVisibleBackgroundUsers enabled even though the UI mode is * {@link Configuration#UI_MODE_TYPE_CAR}. * * @see ActivityTaskManagerService#updateShouldShowDialogsLocked */ private boolean shouldShowDialogsForVisibleBackgroundUserLocked(int userId) { if (!isVisibleBackgroundUser(userId)) { return false; } final int displayId = mWindowManager.mUmInternal.getMainDisplayAssignedToUser(userId); final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId); if (dc == null) { return false; } return shouldShowDialogs(dc.getConfiguration(), /* checkUiMode= */ false); } @Override Loading