Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89f6bfea authored by Zim's avatar Zim
Browse files

Add a new ANR category on BIND_APPLICATION_TIMEOUT

In 6c8b9089701172796c0a520a790112465c431ccb we enabled the feature
to delay scheduling Broadcasts or Services to an app during startup
until after after its bindApplication. This mitigates Broadcast and
Service ANRs caused by slow app startup. What would have been an ANR
is now treated as a slow process startup and apps don't have any
visibility into that.

We now add a new timeout, BIND_APPLICATION_TIMEOUT that starts counting
after we call bindApplication on the app. If we hit the timeout, it means
the app took too long to run its app startup code and we trigger an ANR
so that apps can get explicit feedback on their apps.

Note that the PROC_START_TIMEOUT which always existed now only gets
triggered if we don't get to call bindApplication on the app. This
indicates an OS problem that apps cannot do anything about.

Test: atest ActivityManagerTest
Bug: 253908737

Change-Id: Iaad8d39221dc9b3877d784d8a79f8de1678eea88
parent eaed4f07
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public class TimeoutRecord {
        int APP_REGISTERED = 7;
        int SHORT_FGS_TIMEOUT = 8;
        int JOB_SERVICE = 9;
        int APP_START = 10;
    }

    /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */
@@ -186,4 +187,10 @@ public class TimeoutRecord {
    public static TimeoutRecord forJobService(String reason) {
        return TimeoutRecord.endingNow(TimeoutKind.JOB_SERVICE, reason);
    }

    /** Record for app startup timeout. */
    @NonNull
    public static TimeoutRecord forAppStart(String reason) {
        return TimeoutRecord.endingNow(TimeoutKind.APP_START, reason);
    }
}
+22 −1
Original line number Diff line number Diff line
@@ -559,6 +559,10 @@ public class ActivityManagerService extends IActivityManager.Stub
    // How long we wait for a launched process to attach to the activity manager
    // before we decide it's never going to come up for real.
    static final int PROC_START_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
    // How long we wait for a launched process to complete its app startup before we ANR.
    static final int BIND_APPLICATION_TIMEOUT = 10 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
    // How long we wait to kill an application zygote, after the last process using
    // it has gone away.
    static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000;
@@ -1624,6 +1628,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    static final int UPDATE_CACHED_APP_HIGH_WATERMARK = 79;
    static final int ADD_UID_TO_OBSERVER_MSG = 80;
    static final int REMOVE_UID_FROM_OBSERVER_MSG = 81;
    static final int BIND_APPLICATION_TIMEOUT_MSG = 82;
    static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1976,6 +1981,16 @@ public class ActivityManagerService extends IActivityManager.Stub
                case UPDATE_CACHED_APP_HIGH_WATERMARK: {
                    mAppProfiler.mCachedAppsWatermarkData.updateCachedAppsSnapshot((long) msg.obj);
                } break;
                case BIND_APPLICATION_TIMEOUT_MSG: {
                    ProcessRecord app = (ProcessRecord) msg.obj;
                    final String anrMessage;
                    synchronized (app) {
                        anrMessage = "Process " + app + " failed to complete startup";
                    }
                    mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage));
                } break;
            }
        }
    }
@@ -4734,6 +4749,12 @@ public class ActivityManagerService extends IActivityManager.Stub
                        app.getDisabledCompatChanges(), serializedSystemFontMap,
                        app.getStartElapsedTime(), app.getStartUptime());
            }
            Message msg = mHandler.obtainMessage(BIND_APPLICATION_TIMEOUT_MSG);
            msg.obj = app;
            mHandler.sendMessageDelayed(msg, BIND_APPLICATION_TIMEOUT);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            if (profilerInfo != null) {
                profilerInfo.closeFd();
                profilerInfo = null;
@@ -4808,7 +4829,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        }
        if (app != null && app.getStartUid() == uid && app.getStartSeq() == startSeq) {
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            mHandler.removeMessages(BIND_APPLICATION_TIMEOUT_MSG, app);
        } else {
            Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid
                    + ". Uid: " + uid);