Loading core/java/android/app/Activity.java +3 −0 Original line number Diff line number Diff line Loading @@ -2572,6 +2572,9 @@ public class Activity extends ContextThemeWrapper * entirely drawn your UI and populated with all of the significant data. You * can safely call this method any time after first launch as well, in which case * it will simply be ignored. * <p>If this method is called before the activity's window is <em>first</em> drawn * and displayed as measured by the system, the reported time here will be shifted * to the system measured time. */ public void reportFullyDrawn() { if (mDoReportFullyDrawn) { Loading services/core/java/com/android/server/wm/ActivityMetricsLogger.java +18 −3 Original line number Diff line number Diff line Loading @@ -189,6 +189,8 @@ class ActivityMetricsLogger { private int reason = APP_TRANSITION_TIMEOUT; // TODO(b/132736359) The number may need to consider the visibility change. private int numUndrawnActivities = 1; /** Non-null if the application has reported drawn but its window hasn't. */ private Runnable pendingFullyDrawn; private boolean loggedStartingWindowDrawn; private boolean launchTraceActive; Loading Loading @@ -716,6 +718,9 @@ class ActivityMetricsLogger { BackgroundThread.getHandler().post(() -> logAppTransition( currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot)); BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot)); if (info.pendingFullyDrawn != null) { info.pendingFullyDrawn.run(); } info.launchedActivity.info.launchToken = null; } Loading Loading @@ -839,6 +844,15 @@ class ActivityMetricsLogger { if (info == null) { return null; } if (info.numUndrawnActivities > 0 && info.pendingFullyDrawn == null) { // There are still undrawn activities, postpone reporting fully drawn until all of its // windows are drawn. So that is closer to an usable state. info.pendingFullyDrawn = () -> { logAppTransitionReportedDrawn(r, restoredFromBundle); info.pendingFullyDrawn = null; }; return null; } // Record the handling of the reportFullyDrawn callback in the trace system. This is not // actually used to trace this function, but instead the logical task that this function Loading @@ -849,9 +863,10 @@ class ActivityMetricsLogger { final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN); builder.setPackageName(r.packageName); builder.addTaggedData(FIELD_CLASS_NAME, r.info.name); long currentTimestampNs = SystemClock.elapsedRealtimeNanos(); long startupTimeMs = TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs); final long currentTimestampNs = SystemClock.elapsedRealtimeNanos(); final long startupTimeMs = info.pendingFullyDrawn != null ? info.windowsDrawnDelayMs : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs); builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs); builder.setType(restoredFromBundle ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE Loading services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -195,9 +195,15 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnReportFullyDrawn() { onActivityLaunched(); // The activity reports fully drawn before windows drawn, then the fully drawn event will // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}). mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false); notifyTransitionStarting(); // The pending fully drawn event should send when the actual windows drawn event occurs. notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } Loading Loading
core/java/android/app/Activity.java +3 −0 Original line number Diff line number Diff line Loading @@ -2572,6 +2572,9 @@ public class Activity extends ContextThemeWrapper * entirely drawn your UI and populated with all of the significant data. You * can safely call this method any time after first launch as well, in which case * it will simply be ignored. * <p>If this method is called before the activity's window is <em>first</em> drawn * and displayed as measured by the system, the reported time here will be shifted * to the system measured time. */ public void reportFullyDrawn() { if (mDoReportFullyDrawn) { Loading
services/core/java/com/android/server/wm/ActivityMetricsLogger.java +18 −3 Original line number Diff line number Diff line Loading @@ -189,6 +189,8 @@ class ActivityMetricsLogger { private int reason = APP_TRANSITION_TIMEOUT; // TODO(b/132736359) The number may need to consider the visibility change. private int numUndrawnActivities = 1; /** Non-null if the application has reported drawn but its window hasn't. */ private Runnable pendingFullyDrawn; private boolean loggedStartingWindowDrawn; private boolean launchTraceActive; Loading Loading @@ -716,6 +718,9 @@ class ActivityMetricsLogger { BackgroundThread.getHandler().post(() -> logAppTransition( currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot)); BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot)); if (info.pendingFullyDrawn != null) { info.pendingFullyDrawn.run(); } info.launchedActivity.info.launchToken = null; } Loading Loading @@ -839,6 +844,15 @@ class ActivityMetricsLogger { if (info == null) { return null; } if (info.numUndrawnActivities > 0 && info.pendingFullyDrawn == null) { // There are still undrawn activities, postpone reporting fully drawn until all of its // windows are drawn. So that is closer to an usable state. info.pendingFullyDrawn = () -> { logAppTransitionReportedDrawn(r, restoredFromBundle); info.pendingFullyDrawn = null; }; return null; } // Record the handling of the reportFullyDrawn callback in the trace system. This is not // actually used to trace this function, but instead the logical task that this function Loading @@ -849,9 +863,10 @@ class ActivityMetricsLogger { final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN); builder.setPackageName(r.packageName); builder.addTaggedData(FIELD_CLASS_NAME, r.info.name); long currentTimestampNs = SystemClock.elapsedRealtimeNanos(); long startupTimeMs = TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs); final long currentTimestampNs = SystemClock.elapsedRealtimeNanos(); final long startupTimeMs = info.pendingFullyDrawn != null ? info.windowsDrawnDelayMs : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs); builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs); builder.setType(restoredFromBundle ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE Loading
services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +6 −0 Original line number Diff line number Diff line Loading @@ -195,9 +195,15 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnReportFullyDrawn() { onActivityLaunched(); // The activity reports fully drawn before windows drawn, then the fully drawn event will // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}). mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false); notifyTransitionStarting(); // The pending fully drawn event should send when the actual windows drawn event occurs. notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } Loading