diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2019-10-16 06:15:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-10-16 06:15:26 +0000 |
commit | 6bc75fcbcec5f1f6e228b0dc3efb62b60c764a22 (patch) | |
tree | 6e095e59240cca274f8eff8bce84a1ebbaf3fc2c | |
parent | acb8ee8122c3c5ce8e5acf0d6a4122267ff1d774 (diff) | |
parent | 722d6be12f1ba53a6b3f941c3d3d16a702e68e75 (diff) |
Merge changes from topic "reportFullyDrawn"
* changes:
startop: Add reportFullyDrawn event support in Iorap.
startop: Add timestamps for IntentStarted and ActivityLaunchFinished.
startop: Add reportFullyDrawn event support in framework.
13 files changed, 266 insertions, 85 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2a2d8970f0a1..55cd9339e68c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -900,7 +900,7 @@ public class ActivityManagerService extends IActivityManager.Stub // The other observer methods are unused @Override - public void onIntentStarted(Intent intent) { + public void onIntentStarted(Intent intent, long timestampNs) { } @Override @@ -912,7 +912,11 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void onActivityLaunchFinished(byte[] finalActivity) { + public void onActivityLaunchFinished(byte[] finalActivity, long timestampNs) { + } + + @Override + public void onReportFullyDrawn(byte[] finalActivity, long timestampNs) { } }; diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java index eff0f75466d9..c6b17e24b1de 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java @@ -39,8 +39,13 @@ import java.lang.annotation.RetentionPolicy; * If an activity is successfully started, the launch sequence's state will transition into * {@code STARTED} via {@link #onActivityLaunched}. This is a transient state. * - * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled} - * or into {@code FINISHED} with {@link #onActivityLaunchFinished}. These are terminal states. + * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled}, + * which is a terminal state or into {@code FINISHED} with {@link #onActivityLaunchFinished}. + * + * The {@code FINISHED} with {@link #onActivityLaunchFinished} then may transition to + * {@code FULLY_DRAWN} with {@link #onReportFullyDrawn}, which is a terminal state. + * Note this transition may not happen if the reportFullyDrawn event is not receivied, + * in which case {@code FINISHED} is terminal. * * Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't * necessarily the same within a single launch sequence: it is only the top-most activity at the @@ -51,15 +56,15 @@ import java.lang.annotation.RetentionPolicy; * until a subsequent transition into {@code INTENT_STARTED} initiates a new launch sequence. * * <pre> - * ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ╔══════════════════════════╗ - * ╴╴▶ ⋮ INTENT_STARTED ⋮ ──▶ ⋮ ACTIVITY_LAUNCHED ⋮ ──▶ ║ ACTIVITY_LAUNCH_FINISHED ║ - * └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ ╚══════════════════════════╝ - * : : - * : : - * ▼ ▼ - * ╔════════════════╗ ╔═══════════════════════════╗ - * ║ INTENT_FAILED ║ ║ ACTIVITY_LAUNCH_CANCELLED ║ - * ╚════════════════╝ ╚═══════════════════════════╝ + * ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌--------------------------┐ + * ╴╴▶ INTENT_STARTED ──▶ ACTIVITY_LAUNCHED ──▶ ACTIVITY_LAUNCH_FINISHED + * └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └--------------------------┘ + * : : : + * : : : + * ▼ ▼ ▼ + * ╔════════════════╗ ╔═══════════════════════════╗ ╔═══════════════════════════╗ + * ║ INTENT_FAILED ║ ║ ACTIVITY_LAUNCH_CANCELLED ║ ║ REPORT_FULLY_DRAWN ║ + * ╚════════════════╝ ╚═══════════════════════════╝ ╚═══════════════════════════╝ * </pre> */ public interface ActivityMetricsLaunchObserver { @@ -111,7 +116,7 @@ public interface ActivityMetricsLaunchObserver { * Multiple calls to this method cannot occur without first terminating the current * launch sequence. */ - public void onIntentStarted(@NonNull Intent intent); + public void onIntentStarted(@NonNull Intent intent, long timestampNanos); /** * Notifies the observer that the current launch sequence has failed to launch an activity. @@ -177,6 +182,9 @@ public interface ActivityMetricsLaunchObserver { * drawn for the first time: the top-most activity at the time is what's reported here. * * @param finalActivity the top-most activity whose windows were first to fully draw + * @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds. + * To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted} + * from {@code timestampNanos}. * * Multiple calls to this method cannot occur without first terminating the current * launch sequence. @@ -186,5 +194,22 @@ public interface ActivityMetricsLaunchObserver { * and only the latest activity that was top-most during first-frame drawn * is reported here. */ - public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity); + public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity, + long timestampNanos); + + /** + * Notifies the observer that the application self-reported itself as being fully drawn. + * + * @param activity the activity that triggers the ReportFullyDrawn event. + * @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds. + * To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted} + * from {@code timestampNanos}. + * + * @apiNote The behavior of ReportFullyDrawn mostly depends on the app. + * It is used as an accurate estimate of meanfully app startup time. + * This event may be missing for many apps. + */ + public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity, + long timestampNanos); + } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index ef8c02004116..e6c6b12e18c6 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -92,6 +92,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.server.LocalServices; +import java.util.concurrent.TimeUnit; /** * Listens to activity launches, transitions, visibility changes and window drawn callbacks to @@ -132,8 +133,8 @@ class ActivityMetricsLogger { // set to INVALID_START_TIME in reset. // set to valid value in notifyActivityLaunching - private long mCurrentTransitionStartTime = INVALID_START_TIME; - private long mLastTransitionStartTime = INVALID_START_TIME; + private long mCurrentTransitionStartTimeNs = INVALID_START_TIME; + private long mLastTransitionStartTimeNs = INVALID_START_TIME; private int mCurrentTransitionDeviceUptime; private int mCurrentTransitionDelayMs; @@ -326,12 +327,12 @@ class ActivityMetricsLogger { intent)); } - if (mCurrentTransitionStartTime == INVALID_START_TIME) { + if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) { - mCurrentTransitionStartTime = SystemClock.uptimeMillis(); - mLastTransitionStartTime = mCurrentTransitionStartTime; + mCurrentTransitionStartTimeNs = SystemClock.elapsedRealtimeNanos(); + mLastTransitionStartTimeNs = mCurrentTransitionStartTimeNs; - launchObserverNotifyIntentStarted(intent); + launchObserverNotifyIntentStarted(intent, mCurrentTransitionStartTimeNs); } } @@ -382,14 +383,15 @@ class ActivityMetricsLogger { ? launchedActivity.getWindowingMode() : WINDOWING_MODE_UNDEFINED; final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); - if (mCurrentTransitionStartTime == INVALID_START_TIME) { + if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) { // No transition is active ignore this launch. return; } if (launchedActivity != null && launchedActivity.mDrawn) { // Launched activity is already visible. We cannot measure windows drawn delay. - reset(true /* abort */, info, "launched activity already visible"); + reset(true /* abort */, info, "launched activity already visible", + 0L /* timestampNs */); return; } @@ -407,7 +409,8 @@ class ActivityMetricsLogger { if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) { // Failed to launch or it was not a process switch, so we don't care about the timing. - reset(true /* abort */, info, "failed to launch or not a process switch"); + reset(true /* abort */, info, "failed to launch or not a process switch", + 0L /* timestampNs */); return; } else if (otherWindowModesLaunching) { // Don't log this windowing mode but continue with the other windowing modes. @@ -441,19 +444,20 @@ class ActivityMetricsLogger { * Notifies the tracker that all windows of the app have been drawn. */ WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode, - long timestamp) { + long timestampNs) { if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); if (info == null || info.loggedWindowsDrawn) { return null; } - info.windowsDrawnDelayMs = calculateDelay(timestamp); + info.windowsDrawnDelayMs = calculateDelay(timestampNs); info.loggedWindowsDrawn = true; final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { - reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn"); + reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", + timestampNs /* timestampNs */); } return infoSnapshot; } @@ -476,7 +480,7 @@ class ActivityMetricsLogger { * @param windowingModeToReason A map from windowing mode to a reason integer, which must be on * of ActivityTaskManagerInternal.APP_TRANSITION_* reasons. */ - void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) { + void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestampNs) { if (!isAnyTransitionActive() || mLoggedTransitionStarting) { // Ignore calls to this made after a reset and prior to notifyActivityLaunching. @@ -484,7 +488,7 @@ class ActivityMetricsLogger { return; } if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting"); - mCurrentTransitionDelayMs = calculateDelay(timestamp); + mCurrentTransitionDelayMs = calculateDelay(timestampNs); mLoggedTransitionStarting = true; WindowingModeTransitionInfo foundInfo = null; @@ -501,7 +505,8 @@ class ActivityMetricsLogger { if (allWindowsDrawn()) { // abort metrics collection if we cannot find a matching transition. final boolean abortMetrics = foundInfo == null; - reset(abortMetrics, foundInfo, "notifyTransitionStarting - all windows drawn"); + reset(abortMetrics, foundInfo, "notifyTransitionStarting - all windows drawn", + timestampNs /* timestampNs */); } } @@ -567,7 +572,8 @@ class ActivityMetricsLogger { logAppTransitionCancel(info); mWindowingModeTransitionInfo.remove(r.getWindowingMode()); if (mWindowingModeTransitionInfo.size() == 0) { - reset(true /* abort */, info, "notifyVisibilityChanged to invisible"); + reset(true /* abort */, info, "notifyVisibilityChanged to invisible", + 0L /* timestampNs */); } } } @@ -598,12 +604,16 @@ class ActivityMetricsLogger { } private boolean isAnyTransitionActive() { - return mCurrentTransitionStartTime != INVALID_START_TIME + return mCurrentTransitionStartTimeNs != INVALID_START_TIME && mWindowingModeTransitionInfo.size() > 0; } - private void reset(boolean abort, WindowingModeTransitionInfo info, String cause) { - if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause); + private void reset(boolean abort, WindowingModeTransitionInfo info, String cause, + long timestampNs) { + if (DEBUG_METRICS) { + Slog.i(TAG, + "reset abort=" + abort + ",cause=" + cause + ",timestamp=" + timestampNs); + } if (!abort && isAnyTransitionActive()) { logAppTransitionMultiEvents(); } @@ -615,13 +625,13 @@ class ActivityMetricsLogger { if (abort) { launchObserverNotifyActivityLaunchCancelled(info); } else { - launchObserverNotifyActivityLaunchFinished(info); + launchObserverNotifyActivityLaunchFinished(info, timestampNs); } } else { launchObserverNotifyIntentFailed(); } - mCurrentTransitionStartTime = INVALID_START_TIME; + mCurrentTransitionStartTimeNs = INVALID_START_TIME; mCurrentTransitionDelayMs = INVALID_DELAY; mLoggedTransitionStarting = false; mWindowingModeTransitionInfo.clear(); @@ -629,12 +639,14 @@ class ActivityMetricsLogger { private int calculateCurrentDelay() { // Shouldn't take more than 25 days to launch an app, so int is fine here. - return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime); + return (int) TimeUnit.NANOSECONDS + .toMillis(SystemClock.elapsedRealtimeNanos() - mCurrentTransitionStartTimeNs); } - private int calculateDelay(long timestamp) { + private int calculateDelay(long timestampNs) { // Shouldn't take more than 25 days to launch an app, so int is fine here. - return (int) (timestamp - mCurrentTransitionStartTime); + return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs - + mCurrentTransitionStartTimeNs); } private void logAppTransitionCancel(WindowingModeTransitionInfo info) { @@ -679,7 +691,7 @@ class ActivityMetricsLogger { // Take a snapshot of the transition info before sending it to the handler for logging. // This will avoid any races with other operations that modify the ActivityRecord. final WindowingModeTransitionInfoSnapshot infoSnapshot = - new WindowingModeTransitionInfoSnapshot(info); + new WindowingModeTransitionInfoSnapshot(info); final int currentTransitionDeviceUptime = mCurrentTransitionDeviceUptime; final int currentTransitionDelayMs = mCurrentTransitionDelayMs; BackgroundThread.getHandler().post(() -> logAppTransition( @@ -811,7 +823,9 @@ class ActivityMetricsLogger { final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN); builder.setPackageName(r.packageName); builder.addTaggedData(FIELD_CLASS_NAME, r.info.name); - long startupTimeMs = SystemClock.uptimeMillis() - mLastTransitionStartTime; + long currentTimestampNs = SystemClock.elapsedRealtimeNanos(); + long startupTimeMs = + TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs); builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs); builder.setType(restoredFromBundle ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE @@ -837,6 +851,10 @@ class ActivityMetricsLogger { final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info, r, (int) startupTimeMs); BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot)); + + // Notify reportFullyDrawn event. + launchObserverNotifyReportFullyDrawn(r, currentTimestampNs); + return infoSnapshot; } @@ -1006,12 +1024,12 @@ class ActivityMetricsLogger { } /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */ - private void launchObserverNotifyIntentStarted(Intent intent) { + private void launchObserverNotifyIntentStarted(Intent intent, long timestampNs) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "MetricsLogger:launchObserverNotifyIntentStarted"); // Beginning a launch is timing sensitive and so should be observed as soon as possible. - mLaunchObserver.onIntentStarted(intent); + mLaunchObserver.onIntentStarted(intent, timestampNs); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } @@ -1049,6 +1067,16 @@ class ActivityMetricsLogger { } /** + * Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event. + */ + private void launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, + "MetricsLogger:launchObserverNotifyReportFullyDrawn"); + mLaunchObserver.onReportFullyDrawn(convertActivityRecordToProto(r), timestampNs); + Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + } + + /** * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is * cancelled. */ @@ -1068,12 +1096,14 @@ class ActivityMetricsLogger { * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity * has fully finished (successfully). */ - private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info) { + private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info, + long timestampNs) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "MetricsLogger:launchObserverNotifyActivityLaunchFinished"); - mLaunchObserver.onActivityLaunchFinished( - convertActivityRecordToProto(info.launchedActivity)); + mLaunchObserver + .onActivityLaunchFinished(convertActivityRecordToProto(info.launchedActivity), + timestampNs); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index dccf251bf688..76a551fffa34 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3106,7 +3106,7 @@ final class ActivityRecord extends AppWindowToken { void reportFullyDrawnLocked(boolean restoredFromBundle) { final WindowingModeTransitionInfoSnapshot info = mStackSupervisor - .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); + .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); if (info != null) { mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, info.windowsFullyDrawnDelayMs, info.getLaunchState()); @@ -3114,13 +3114,13 @@ final class ActivityRecord extends AppWindowToken { } /** Called when the windows associated app window container are drawn. */ - void onWindowsDrawn(boolean drawn, long timestamp) { + void onWindowsDrawn(boolean drawn, long timestampNs) { mDrawn = drawn; if (!drawn) { return; } final WindowingModeTransitionInfoSnapshot info = mStackSupervisor - .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestamp); + .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestampNs); final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY; final @LaunchState int launchState = info != null ? info.getLaunchState() : -1; mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index ab35652eb525..0488a3b7065b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -159,10 +159,10 @@ public abstract class ActivityTaskManagerInternal { * * @param reasons A map from windowing mode to a reason integer why the transition was started, * which must be one of the APP_TRANSITION_* values. - * @param timestamp The time at which the app transition started in - * {@link SystemClock#uptimeMillis()} timebase. + * @param timestampNs The time at which the app transition started in + * {@link SystemClock#elapsedRealtimeNs()} ()} timebase. */ - public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp); + public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestampNs); /** * Callback for window manager to let activity manager know that the app transition was diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index dffdcd80d766..20113a68fdc6 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6012,10 +6012,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void notifyAppTransitionStarting(SparseIntArray reasons, - long timestamp) { + long timestampNs) { synchronized (mGlobalLock) { mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting( - reasons, timestamp); + reasons, timestampNs); } } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 894dfd4065a4..0c07e15b9da5 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -209,7 +209,7 @@ public class AppTransitionController { mDisplayContent.computeImeTarget(true /* updateImeTarget */); mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(), - SystemClock.uptimeMillis()); + SystemClock.elapsedRealtimeNanos()); if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) { mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index b606412ddb76..e56fdd244d4f 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -512,7 +512,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" + numInteresting + " visible=" + numVisible); if (nowDrawn != reportedDrawn) { - onWindowsDrawn(nowDrawn, SystemClock.uptimeMillis()); + onWindowsDrawn(nowDrawn, SystemClock.elapsedRealtimeNanos()); reportedDrawn = nowDrawn; } if (nowVisible != reportedVisible) { diff --git a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java index 93e2d8d6fba4..362ed3c380c5 100644 --- a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java +++ b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java @@ -70,9 +70,12 @@ class LaunchObserverRegistryImpl implements } @Override - public void onIntentStarted(Intent intent) { + public void onIntentStarted(Intent intent, long timestampNs) { mHandler.sendMessage(PooledLambda.obtainMessage( - LaunchObserverRegistryImpl::handleOnIntentStarted, this, intent)); + LaunchObserverRegistryImpl::handleOnIntentStarted, + this, + intent, + timestampNs)); } @Override @@ -99,9 +102,22 @@ class LaunchObserverRegistryImpl implements @Override public void onActivityLaunchFinished( - @ActivityRecordProto byte[] activity) { + @ActivityRecordProto byte[] activity, + long timestampNs) { + mHandler.sendMessage(PooledLambda.obtainMessage( + LaunchObserverRegistryImpl::handleOnActivityLaunchFinished, + this, + activity, + timestampNs)); + } + + @Override + public void onReportFullyDrawn(@ActivityRecordProto byte[] activity, long timestampNs) { mHandler.sendMessage(PooledLambda.obtainMessage( - LaunchObserverRegistryImpl::handleOnActivityLaunchFinished, this, activity)); + LaunchObserverRegistryImpl::handleOnReportFullyDrawn, + this, + activity, + timestampNs)); } // Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be @@ -116,11 +132,11 @@ class LaunchObserverRegistryImpl implements mList.remove(observer); } - private void handleOnIntentStarted(Intent intent) { + private void handleOnIntentStarted(Intent intent, long timestampNs) { // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. for (int i = 0; i < mList.size(); i++) { ActivityMetricsLaunchObserver o = mList.get(i); - o.onIntentStarted(intent); + o.onIntentStarted(intent, timestampNs); } } @@ -152,11 +168,20 @@ class LaunchObserverRegistryImpl implements } private void handleOnActivityLaunchFinished( - @ActivityRecordProto byte[] activity) { + @ActivityRecordProto byte[] activity, long timestampNs) { + // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. + for (int i = 0; i < mList.size(); i++) { + ActivityMetricsLaunchObserver o = mList.get(i); + o.onActivityLaunchFinished(activity, timestampNs); + } + } + + private void handleOnReportFullyDrawn( + @ActivityRecordProto byte[] activity, long timestampNs) { // Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee. for (int i = 0; i < mList.size(); i++) { ActivityMetricsLaunchObserver o = mList.get(i); - o.onActivityLaunchFinished(activity); + o.onReportFullyDrawn(activity, timestampNs); } } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 68324df48af8..d606e5d8c1a2 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -503,7 +503,8 @@ public class RecentsAnimationController implements DeathRecipient { } final SparseIntArray reasons = new SparseIntArray(); reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM); - mService.mAtmInternal.notifyAppTransitionStarting(reasons, SystemClock.uptimeMillis()); + mService.mAtmInternal + .notifyAppTransitionStarting(reasons, SystemClock.elapsedRealtimeNanos()); } private RemoteAnimationTarget[] createAppAnimations() { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index aaaa7a5ab596..2836e69f79da 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.timeout; @@ -128,7 +129,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { mActivityMetricsLogger.notifyActivityLaunching(intent); - verifyAsync(mLaunchObserver).onIntentStarted(eq(intent)); + verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } @@ -163,12 +164,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { testOnActivityLaunched(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), - SystemClock.uptimeMillis()); + SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(), - SystemClock.uptimeMillis()); + SystemClock.elapsedRealtimeNanos()); - verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord)); + verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } @@ -186,6 +187,16 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } @Test + public void testOnReportFullyDrawn() throws Exception { + testOnActivityLaunched(); + + mActivityMetricsLogger.logAppTransitionReportedDrawn(mActivityRecord, false); + + verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mActivityRecord), anyLong()); + verifyNoMoreInteractions(mLaunchObserver); + } + + @Test public void testOnActivityLaunchedTrampoline() throws Exception { testOnIntentStarted(); @@ -206,12 +217,13 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { testOnActivityLaunchedTrampoline(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), - SystemClock.uptimeMillis()); + SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(), - SystemClock.uptimeMillis()); + SystemClock.elapsedRealtimeNanos()); - verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline)); + verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline), + anyLong()); verifyNoMoreInteractions(mLaunchObserver); } diff --git a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java index acf994610182..cf120cf687fb 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java +++ b/startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java @@ -86,10 +86,14 @@ public abstract class AppLaunchEvent implements Parcelable { public static final class IntentStarted extends AppLaunchEvent { @NonNull public final Intent intent; + public final long timestampNs; - public IntentStarted(@SequenceId long sequenceId, Intent intent) { + public IntentStarted(@SequenceId long sequenceId, + Intent intent, + long timestampNs) { super(sequenceId); this.intent = intent; + this.timestampNs = timestampNs; Objects.requireNonNull(intent, "intent"); } @@ -98,14 +102,16 @@ public abstract class AppLaunchEvent implements Parcelable { public boolean equals(Object other) { if (other instanceof IntentStarted) { return intent.equals(((IntentStarted)other).intent) && - super.equals(other); + timestampNs == ((IntentStarted)other).timestampNs && + super.equals(other); } return false; } @Override protected String toStringBody() { - return ", intent=" + intent.toString(); + return ", intent=" + intent.toString() + + " , timestampNs=" + Long.toString(timestampNs); } @@ -113,11 +119,13 @@ public abstract class AppLaunchEvent implements Parcelable { protected void writeToParcelImpl(Parcel p, int flags) { super.writeToParcelImpl(p, flags); IntentProtoParcelable.write(p, intent, flags); + p.writeLong(timestampNs); } IntentStarted(Parcel p) { super(p); intent = IntentProtoParcelable.create(p); + timestampNs = p.readLong(); } } @@ -216,18 +224,39 @@ public abstract class AppLaunchEvent implements Parcelable { } public static final class ActivityLaunchFinished extends BaseWithActivityRecordData { + public final long timestampNs; + public ActivityLaunchFinished(@SequenceId long sequenceId, - @NonNull @ActivityRecordProto byte[] snapshot) { + @NonNull @ActivityRecordProto byte[] snapshot, + long timestampNs) { super(sequenceId, snapshot); + this.timestampNs = timestampNs; } @Override public boolean equals(Object other) { if (other instanceof ActivityLaunched) { - return super.equals(other); + return timestampNs == ((ActivityLaunchFinished)other).timestampNs && + super.equals(other); } return false; } + + @Override + protected String toStringBody() { + return ", timestampNs=" + Long.toString(timestampNs); + } + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + p.writeLong(timestampNs); + } + + ActivityLaunchFinished(Parcel p) { + super(p); + timestampNs = p.readLong(); + } } public static class ActivityLaunchCancelled extends AppLaunchEvent { @@ -275,6 +304,42 @@ public abstract class AppLaunchEvent implements Parcelable { } } + public static final class ReportFullyDrawn extends BaseWithActivityRecordData { + public final long timestampNs; + + public ReportFullyDrawn(@SequenceId long sequenceId, + @NonNull @ActivityRecordProto byte[] snapshot, + long timestampNs) { + super(sequenceId, snapshot); + this.timestampNs = timestampNs; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ReportFullyDrawn) { + return timestampNs == ((ReportFullyDrawn)other).timestampNs && + super.equals(other); + } + return false; + } + + @Override + protected String toStringBody() { + return ", timestampNs=" + Long.toString(timestampNs); + } + + @Override + protected void writeToParcelImpl(Parcel p, int flags) { + super.writeToParcelImpl(p, flags); + p.writeLong(timestampNs); + } + + ReportFullyDrawn(Parcel p) { + super(p); + timestampNs = p.readLong(); + } + } + @Override public @ContentsFlags int describeContents() { return 0; } @@ -348,6 +413,7 @@ public abstract class AppLaunchEvent implements Parcelable { ActivityLaunched.class, ActivityLaunchFinished.class, ActivityLaunchCancelled.class, + ReportFullyDrawn.class, }; public static class ActivityRecordProtoParcelable { diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java index 902da4c0f72e..f753548516ef 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java +++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java @@ -315,19 +315,19 @@ public class IorapForwardingService extends SystemService { // All callbacks occur on the same background thread. Don't synchronize explicitly. @Override - public void onIntentStarted(@NonNull Intent intent) { + public void onIntentStarted(@NonNull Intent intent, long timestampNs) { // #onIntentStarted [is the only transition that] initiates a new launch sequence. ++mSequenceId; if (DEBUG) { - Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)", - mSequenceId, intent)); + Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s, %d)", + mSequenceId, intent, timestampNs)); } invokeRemote(mIorapRemote, (IIorap remote) -> remote.onAppLaunchEvent(RequestId.nextValueForSequence(), - new AppLaunchEvent.IntentStarted(mSequenceId, intent)) + new AppLaunchEvent.IntentStarted(mSequenceId, intent, timestampNs)) ); } @@ -374,16 +374,34 @@ public class IorapForwardingService extends SystemService { } @Override - public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) { + public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity, + long timestampNs) { if (DEBUG) { - Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)", - mSequenceId, activity)); + Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s, %d)", + mSequenceId, activity, timestampNs)); + } + + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onAppLaunchEvent(RequestId.nextValueForSequence(), + new AppLaunchEvent.ActivityLaunchFinished(mSequenceId, + activity, + timestampNs)) + ); + } + + @Override + public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity, + long timestampNs) { + if (DEBUG) { + Log.v(TAG, String.format("AppLaunchObserver#onReportFullyDrawn(%d, %s, %d)", + mSequenceId, activity, timestampNs)); } invokeRemote(mIorapRemote, (IIorap remote) -> remote.onAppLaunchEvent(RequestId.nextValueForSequence(), - new AppLaunchEvent.ActivityLaunchFinished(mSequenceId, activity)) + new AppLaunchEvent.ReportFullyDrawn(mSequenceId, activity, timestampNs)) ); } } |