From ebede9715f163768af50e804454c210d74725093 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 3 Feb 2021 14:40:23 +0000 Subject: [PATCH] Add AnrController to control ANR dialog delay This will be used in subsequent cls to allow the StorageManagerService delay the ANR dialog for an app undergoing transcoding at the time of ANR Test: Manual Bug: 170486601 Change-Id: I5431d22bd8faa75e3deab1960a2f721784f98d42 --- .../android/app/ActivityManagerInternal.java | 6 ++++ core/java/android/app/AnrController.java | 29 +++++++++++++++ .../server/am/ActivityManagerService.java | 11 ++++++ .../server/am/ProcessErrorStateRecord.java | 10 +++++- .../server/wm/ActivityTaskManagerService.java | 36 +++++++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 core/java/android/app/AnrController.java diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 9b6f4b43581bc..c31c22cca329a 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -538,4 +538,10 @@ public abstract class ActivityManagerInternal { * @return mBootTimeTempAllowlistDuration of ActivityManagerConstants. */ public abstract long getBootTimeTempAllowListDuration(); + + /** Register an {@link AnrController} to control the ANR dialog behavior */ + public abstract void registerAnrController(AnrController controller); + + /** Unregister an {@link AnrController} */ + public abstract void unregisterAnrController(AnrController controller); } diff --git a/core/java/android/app/AnrController.java b/core/java/android/app/AnrController.java new file mode 100644 index 0000000000000..cfc9d27157200 --- /dev/null +++ b/core/java/android/app/AnrController.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +/** + * Interface to control the ANR dialog within the activity manager + * {@hide} + */ +public interface AnrController { + /** + * Returns the delay in milliseconds for an ANR dialog that is about to be shown for + * {@code packageName}. + */ + long getAnrDelayMillis(String packageName, int uid); +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ecb915f49bc3a..799012ab17ef0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -145,6 +145,7 @@ import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManagerInternal; import android.app.ActivityTaskManager.RootTaskInfo; import android.app.ActivityThread; +import android.app.AnrController; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal.CheckOpsDelegate; @@ -15861,6 +15862,16 @@ public class ActivityManagerService extends IActivityManager.Stub // PackageManagerService. return mConstants.mBootTimeTempAllowlistDuration; } + + @Override + public void registerAnrController(AnrController controller) { + mActivityTaskManager.registerAnrController(controller); + } + + @Override + public void unregisterAnrController(AnrController controller) { + mActivityTaskManager.unregisterAnrController(controller); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 64e307a5f1820..165312352990a 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -416,6 +416,14 @@ class ProcessErrorStateRecord { return; } + // Retrieve max ANR delay from AnrControllers without the mService lock since the + // controllers might in turn call into apps + long anrDialogDelayMs = mService.mActivityTaskManager.getMaxAnrDelayMillis(aInfo); + if (aInfo != null && aInfo.packageName != null && anrDialogDelayMs > 0) { + Slog.i(TAG, "Delaying ANR dialog for " + aInfo.packageName + " for " + anrDialogDelayMs + + "ms"); + } + synchronized (mService) { // mBatteryStatsService can be null if the AMS is constructed with injector only. This // will only happen in tests. @@ -447,7 +455,7 @@ class ProcessErrorStateRecord { msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem); - mService.mUiHandler.sendMessage(msg); + mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs); } } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 2d6e9b2c68c52..4bcef408d9a0b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -130,6 +130,7 @@ import android.app.ActivityTaskManager; import android.app.ActivityTaskManager.RootTaskInfo; import android.app.ActivityThread; import android.app.AlertDialog; +import android.app.AnrController; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.Dialog; @@ -494,6 +495,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ private volatile long mLastStopAppSwitchesTime; + private final List mAnrController = new ArrayList<>(); IActivityController mController = null; boolean mControllerIsAMonkey = false; @@ -2058,6 +2060,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAppSwitchesAllowed; } + /** Register an {@link AnrController} to control the ANR dialog behavior */ + public void registerAnrController(AnrController controller) { + synchronized (mGlobalLock) { + mAnrController.add(controller); + } + } + + /** Unregister an {@link AnrController} */ + public void unregisterAnrController(AnrController controller) { + synchronized (mGlobalLock) { + mAnrController.remove(controller); + } + } + + /** @return the max ANR delay from all registered {@link AnrController} instances */ + public long getMaxAnrDelayMillis(ApplicationInfo info) { + if (info == null || info.packageName == null) { + return 0; + } + + final ArrayList controllers; + synchronized (mGlobalLock) { + controllers = new ArrayList<>(mAnrController); + } + + final String packageName = info.packageName; + long maxDelayMs = 0; + for (AnrController controller : controllers) { + maxDelayMs = Math.max(maxDelayMs, controller.getAnrDelayMillis(packageName, info.uid)); + } + maxDelayMs = Math.max(maxDelayMs, 0); + return maxDelayMs; + } + @Override public void setActivityController(IActivityController controller, boolean imAMonkey) { mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,