diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index b2fd169ff55c8..3fa89279e9cc9 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -761,6 +761,7 @@ public class Activity extends ContextThemeWrapper boolean mStartedActivity; private boolean mDestroyed; private boolean mDoReportFullyDrawn = true; + private boolean mRestoredFromBundle; /** true if the activity is going through a transient pause */ /*package*/ boolean mTemporaryPause = false; /** true if the activity is being destroyed in order to recreate it with a new configuration */ @@ -1012,6 +1013,7 @@ public class Activity extends ContextThemeWrapper if (mVoiceInteractor != null) { mVoiceInteractor.attachActivity(this); } + mRestoredFromBundle = savedInstanceState != null; mCalled = true; } @@ -1948,7 +1950,7 @@ public class Activity extends ContextThemeWrapper if (mDoReportFullyDrawn) { mDoReportFullyDrawn = false; try { - ActivityManager.getService().reportActivityFullyDrawn(mToken); + ActivityManager.getService().reportActivityFullyDrawn(mToken, mRestoredFromBundle); } catch (RemoteException e) { } } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index fa9d7ca8ebc57..897e42bc2b226 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -376,7 +376,7 @@ interface IActivityManager { boolean convertFromTranslucent(in IBinder token); boolean convertToTranslucent(in IBinder token, in Bundle options); void notifyActivityDrawn(in IBinder token); - void reportActivityFullyDrawn(in IBinder token); + void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle); void restart(); void performIdleMaintenance(); void takePersistableUriPermission(in Uri uri, int modeFlags, int userId); diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 8d7afc23c6a8a..0c787dbfc3161 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -62,6 +62,14 @@ message MetricsEvent { // The action failed TYPE_FAILURE = 11; + + // Type for APP_TRANSITION_REPORTED_DRAWN event: The activity was started without restoring from + // a bundle. + TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE = 12; + + // Type for APP_TRANSITION_REPORTED_DRAWN event: The activity was started with restoring from + // a bundle. + TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE = 13; } // Types of alerts, as bit field values @@ -4265,6 +4273,14 @@ message MetricsEvent { // FIELD: The numeric preference value (of type int) when it is changed in Settings FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE = 1089; + // ACTION: Logged when the app has notified that it has fully drawn. See + // Activity.reportFullyDrawn(). + APP_TRANSITION_REPORTED_DRAWN = 1090; + + // FIELD: The delay of the activity reporting to be fully drawn measured from the beginning of + // the app transition. + APP_TRANSITION_REPORTED_DRAWN_MS = 1091; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 30e5a2cdba9d6..45387bd4b3634 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4902,13 +4902,13 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void reportActivityFullyDrawn(IBinder token) { + public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) { synchronized (this) { ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { return; } - r.reportFullyDrawnLocked(); + r.reportFullyDrawnLocked(restoredFromBundle); } } diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 98815d7e18c7c..31e74428a8b0a 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -15,12 +15,17 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TR import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -67,12 +72,14 @@ class ActivityMetricsLogger { private final MetricsLogger mMetricsLogger = new MetricsLogger(); private long mCurrentTransitionStartTime = INVALID_START_TIME; + private long mLastTransitionStartTime = INVALID_START_TIME; private int mCurrentTransitionDeviceUptime; private int mCurrentTransitionDelayMs; private boolean mLoggedTransitionStarting; private final SparseArray mStackTransitionInfo = new SparseArray<>(); + private final SparseArray mLastStackTransitionInfo = new SparseArray<>(); private final class StackTransitionInfo { private ActivityRecord launchedActivity; @@ -136,6 +143,7 @@ class ActivityMetricsLogger { void notifyActivityLaunching() { if (!isAnyTransitionActive()) { mCurrentTransitionStartTime = SystemClock.uptimeMillis(); + mLastTransitionStartTime = mCurrentTransitionStartTime; } } @@ -223,7 +231,8 @@ class ActivityMetricsLogger { newInfo.launchedActivity = launchedActivity; newInfo.currentTransitionProcessRunning = processRunning; newInfo.startResult = resultCode; - mStackTransitionInfo.append(stackId, newInfo); + mStackTransitionInfo.put(stackId, newInfo); + mLastStackTransitionInfo.put(stackId, newInfo); mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000); } @@ -388,6 +397,24 @@ class ActivityMetricsLogger { } } + void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) { + final StackTransitionInfo info = mLastStackTransitionInfo.get(r.getStackId()); + if (info == null) { + return; + } + final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN); + builder.setPackageName(r.packageName); + builder.addTaggedData(FIELD_CLASS_NAME, r.info.name); + builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, + SystemClock.uptimeMillis() - mLastTransitionStartTime); + builder.setType(restoredFromBundle + ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE + : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE); + builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING, + info.currentTransitionProcessRunning ? 1 : 0); + mMetricsLogger.write(builder); + } + private int getTransitionType(StackTransitionInfo info) { if (info.currentTransitionProcessRunning) { if (info.startResult == START_SUCCESS) { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 995ac37267441..44727c35132d5 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1836,7 +1836,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } } - public void reportFullyDrawnLocked() { + public void reportFullyDrawnLocked(boolean restoredFromBundle) { final long curTime = SystemClock.uptimeMillis(); if (displayStartTime != 0) { reportLaunchTimeLocked(curTime); @@ -1869,6 +1869,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } stack.mFullyDrawnStartTime = 0; } + mStackSupervisor.mActivityMetricsLogger.logAppTransitionReportedDrawn(this, + restoredFromBundle); fullyDrawnStartTime = 0; }