summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2019-10-16 06:15:26 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-10-16 06:15:26 +0000
commit6bc75fcbcec5f1f6e228b0dc3efb62b60c764a22 (patch)
tree6e095e59240cca274f8eff8bce84a1ebbaf3fc2c
parentacb8ee8122c3c5ce8e5acf0d6a4122267ff1d774 (diff)
parent722d6be12f1ba53a6b3f941c3d3d16a702e68e75 (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.
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java51
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java92
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java2
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java41
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java26
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/AppLaunchEvent.java76
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java34
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))
);
}
}