Loading services/core/java/com/android/server/wm/ActivityMetricsLogger.java +26 −21 Original line number Diff line number Diff line Loading @@ -403,8 +403,7 @@ class ActivityMetricsLogger { if (launchedActivity != null && launchedActivity.mDrawn) { // Launched activity is already visible. We cannot measure windows drawn delay. reset(true /* abort */, info, "launched activity already visible", 0L /* timestampNs */); abort(info, "launched activity already visible"); return; } Loading @@ -422,8 +421,7 @@ 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", 0L /* timestampNs */); abort(info, "failed to launch or not a process switch"); return; } else if (otherWindowModesLaunching) { // Don't log this windowing mode but continue with the other windowing modes. Loading Loading @@ -469,8 +467,7 @@ class ActivityMetricsLogger { final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs /* timestampNs */); reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs); } return infoSnapshot; } Loading Loading @@ -544,10 +541,11 @@ class ActivityMetricsLogger { mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget(); } private boolean hasVisibleNonFinishingActivity(TaskRecord t) { /** @return {@code true} if the given task has an activity will be drawn. */ private static boolean hasActivityToBeDrawn(TaskRecord t) { for (int i = t.getChildCount() - 1; i >= 0; --i) { final ActivityRecord r = t.getChildAt(i); if (r.visible && !r.finishing) { if (r.visible && !r.mDrawn && !r.finishing) { return true; } } Loading @@ -574,19 +572,20 @@ class ActivityMetricsLogger { return; } // Check if there is any activity in the task that is visible and not finishing. If the // launched activity finished before it is drawn and if there is another activity in // the task then that activity will be draw on screen. if (hasVisibleNonFinishingActivity(t)) { // If the task of the launched activity contains any activity to be drawn, then the // window drawn event should report later to complete the transition. Otherwise all // activities in this task may be finished, invisible or drawn, so the transition event // should be cancelled. if (hasActivityToBeDrawn(t)) { return; } if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r); logAppTransitionCancel(info); mWindowingModeTransitionInfo.remove(r.getWindowingMode()); if (mWindowingModeTransitionInfo.size() == 0) { reset(true /* abort */, info, "notifyVisibilityChanged to invisible", 0L /* timestampNs */); // Abort if this is the only one active transition. if (mWindowingModeTransitionInfo.size() == 1 && mWindowingModeTransitionInfo.get(r.getWindowingMode()) != null) { abort(info, "notifyVisibilityChanged to invisible"); } } } Loading Loading @@ -622,19 +621,25 @@ class ActivityMetricsLogger { && mWindowingModeTransitionInfo.size() > 0; } /** Aborts tracking of current launch metrics. */ private void abort(WindowingModeTransitionInfo info, String cause) { reset(true /* abort */, info, cause, 0L /* timestampNs */); } private void reset(boolean abort, WindowingModeTransitionInfo info, String cause, long timestampNs) { final boolean isAnyTransitionActive = isAnyTransitionActive(); if (DEBUG_METRICS) { Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause + ",timestamp=" + timestampNs); Slog.i(TAG, "reset abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs + " active=" + isAnyTransitionActive); } if (!abort && isAnyTransitionActive()) { if (!abort && isAnyTransitionActive) { logAppTransitionMultiEvents(); } stopLaunchTrace(info); // Ignore reset-after reset. if (isAnyTransitionActive()) { if (isAnyTransitionActive) { // LaunchObserver callbacks. if (abort) { launchObserverNotifyActivityLaunchCancelled(info); Loading services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +39 −17 Original line number Diff line number Diff line Loading @@ -149,9 +149,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchFinished() { onActivityLaunched(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); notifyTransitionStarting(); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); Loading @@ -159,10 +157,10 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } @Test public void testOnActivityLaunchCancelled() { public void testOnActivityLaunchCancelled_hasDrawn() { onActivityLaunched(); mTopActivity.mDrawn = true; mTopActivity.visible = mTopActivity.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); Loading @@ -171,6 +169,28 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { verifyNoMoreInteractions(mLaunchObserver); } @Test public void testOnActivityLaunchCancelled_finishedBeforeDrawn() { mTopActivity.visible = mTopActivity.mDrawn = true; // Suppress resume when creating the record because we want to notify logger manually. mSupervisor.beginDeferResume(); // Create an activity with different process that meets process switch. final ActivityRecord noDrawnActivity = new ActivityBuilder(mService) .setTask(mTopActivity.getTaskRecord()) .setProcessName("other") .build(); mSupervisor.readyToResume(); mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity); noDrawnActivity.destroyIfPossible("test"); mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity)); } @Test public void testOnReportFullyDrawn() { onActivityLaunched(); Loading @@ -184,16 +204,21 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private void onActivityLaunchedTrampoline() { onIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt()); // A second, distinct, activity launch is coalesced into the the current app launch sequence mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); // A second, distinct, activity launch is coalesced into the current app launch sequence. mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); verifyNoMoreInteractions(mLaunchObserver); } private void notifyTransitionStarting() { mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); } private void notifyWindowsDrawn(ActivityRecord r) { mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(), SystemClock.elapsedRealtimeNanos()); Loading @@ -203,15 +228,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchFinishedTrampoline() { onActivityLaunchedTrampoline(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); notifyTransitionStarting(); notifyWindowsDrawn(mTrampolineActivity); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } Loading @@ -219,12 +241,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchCancelledTrampoline() { onActivityLaunchedTrampoline(); mTrampolineActivity.mDrawn = true; mTopActivity.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity); mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity)); verifyNoMoreInteractions(mLaunchObserver); } Loading services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +9 −2 Original line number Diff line number Diff line Loading @@ -118,7 +118,8 @@ class ActivityTestsBase extends SystemServiceTestsBase { private ComponentName mComponent; private String mTargetActivity; private TaskRecord mTaskRecord; private int mUid; private String mProcessName = "name"; private int mUid = 12345; private boolean mCreateTask; private ActivityStack mStack; private int mActivityFlags; Loading Loading @@ -175,6 +176,11 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } ActivityBuilder setProcessName(String name) { mProcessName = name; return this; } ActivityBuilder setUid(int uid) { mUid = uid; return this; Loading Loading @@ -235,6 +241,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; aInfo.processName = mProcessName; aInfo.packageName = mComponent.getPackageName(); if (mTargetActivity != null) { aInfo.targetActivity = mTargetActivity; Loading Loading @@ -268,7 +275,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { } final WindowProcessController wpc = new WindowProcessController(mService, mService.mContext.getApplicationInfo(), "name", 12345, mService.mContext.getApplicationInfo(), mProcessName, mUid, UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); Loading Loading
services/core/java/com/android/server/wm/ActivityMetricsLogger.java +26 −21 Original line number Diff line number Diff line Loading @@ -403,8 +403,7 @@ class ActivityMetricsLogger { if (launchedActivity != null && launchedActivity.mDrawn) { // Launched activity is already visible. We cannot measure windows drawn delay. reset(true /* abort */, info, "launched activity already visible", 0L /* timestampNs */); abort(info, "launched activity already visible"); return; } Loading @@ -422,8 +421,7 @@ 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", 0L /* timestampNs */); abort(info, "failed to launch or not a process switch"); return; } else if (otherWindowModesLaunching) { // Don't log this windowing mode but continue with the other windowing modes. Loading Loading @@ -469,8 +467,7 @@ class ActivityMetricsLogger { final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs /* timestampNs */); reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs); } return infoSnapshot; } Loading Loading @@ -544,10 +541,11 @@ class ActivityMetricsLogger { mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget(); } private boolean hasVisibleNonFinishingActivity(TaskRecord t) { /** @return {@code true} if the given task has an activity will be drawn. */ private static boolean hasActivityToBeDrawn(TaskRecord t) { for (int i = t.getChildCount() - 1; i >= 0; --i) { final ActivityRecord r = t.getChildAt(i); if (r.visible && !r.finishing) { if (r.visible && !r.mDrawn && !r.finishing) { return true; } } Loading @@ -574,19 +572,20 @@ class ActivityMetricsLogger { return; } // Check if there is any activity in the task that is visible and not finishing. If the // launched activity finished before it is drawn and if there is another activity in // the task then that activity will be draw on screen. if (hasVisibleNonFinishingActivity(t)) { // If the task of the launched activity contains any activity to be drawn, then the // window drawn event should report later to complete the transition. Otherwise all // activities in this task may be finished, invisible or drawn, so the transition event // should be cancelled. if (hasActivityToBeDrawn(t)) { return; } if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r); logAppTransitionCancel(info); mWindowingModeTransitionInfo.remove(r.getWindowingMode()); if (mWindowingModeTransitionInfo.size() == 0) { reset(true /* abort */, info, "notifyVisibilityChanged to invisible", 0L /* timestampNs */); // Abort if this is the only one active transition. if (mWindowingModeTransitionInfo.size() == 1 && mWindowingModeTransitionInfo.get(r.getWindowingMode()) != null) { abort(info, "notifyVisibilityChanged to invisible"); } } } Loading Loading @@ -622,19 +621,25 @@ class ActivityMetricsLogger { && mWindowingModeTransitionInfo.size() > 0; } /** Aborts tracking of current launch metrics. */ private void abort(WindowingModeTransitionInfo info, String cause) { reset(true /* abort */, info, cause, 0L /* timestampNs */); } private void reset(boolean abort, WindowingModeTransitionInfo info, String cause, long timestampNs) { final boolean isAnyTransitionActive = isAnyTransitionActive(); if (DEBUG_METRICS) { Slog.i(TAG, "reset abort=" + abort + ",cause=" + cause + ",timestamp=" + timestampNs); Slog.i(TAG, "reset abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs + " active=" + isAnyTransitionActive); } if (!abort && isAnyTransitionActive()) { if (!abort && isAnyTransitionActive) { logAppTransitionMultiEvents(); } stopLaunchTrace(info); // Ignore reset-after reset. if (isAnyTransitionActive()) { if (isAnyTransitionActive) { // LaunchObserver callbacks. if (abort) { launchObserverNotifyActivityLaunchCancelled(info); Loading
services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +39 −17 Original line number Diff line number Diff line Loading @@ -149,9 +149,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchFinished() { onActivityLaunched(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); notifyTransitionStarting(); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); Loading @@ -159,10 +157,10 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } @Test public void testOnActivityLaunchCancelled() { public void testOnActivityLaunchCancelled_hasDrawn() { onActivityLaunched(); mTopActivity.mDrawn = true; mTopActivity.visible = mTopActivity.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); Loading @@ -171,6 +169,28 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { verifyNoMoreInteractions(mLaunchObserver); } @Test public void testOnActivityLaunchCancelled_finishedBeforeDrawn() { mTopActivity.visible = mTopActivity.mDrawn = true; // Suppress resume when creating the record because we want to notify logger manually. mSupervisor.beginDeferResume(); // Create an activity with different process that meets process switch. final ActivityRecord noDrawnActivity = new ActivityBuilder(mService) .setTask(mTopActivity.getTaskRecord()) .setProcessName("other") .build(); mSupervisor.readyToResume(); mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity); noDrawnActivity.destroyIfPossible("test"); mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity)); } @Test public void testOnReportFullyDrawn() { onActivityLaunched(); Loading @@ -184,16 +204,21 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private void onActivityLaunchedTrampoline() { onIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt()); // A second, distinct, activity launch is coalesced into the the current app launch sequence mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); // A second, distinct, activity launch is coalesced into the current app launch sequence. mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); verifyNoMoreInteractions(mLaunchObserver); } private void notifyTransitionStarting() { mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); } private void notifyWindowsDrawn(ActivityRecord r) { mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(), SystemClock.elapsedRealtimeNanos()); Loading @@ -203,15 +228,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchFinishedTrampoline() { onActivityLaunchedTrampoline(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); notifyTransitionStarting(); notifyWindowsDrawn(mTrampolineActivity); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); } Loading @@ -219,12 +241,12 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { public void testOnActivityLaunchCancelledTrampoline() { onActivityLaunchedTrampoline(); mTrampolineActivity.mDrawn = true; mTopActivity.mDrawn = true; // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity); mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity)); verifyNoMoreInteractions(mLaunchObserver); } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +9 −2 Original line number Diff line number Diff line Loading @@ -118,7 +118,8 @@ class ActivityTestsBase extends SystemServiceTestsBase { private ComponentName mComponent; private String mTargetActivity; private TaskRecord mTaskRecord; private int mUid; private String mProcessName = "name"; private int mUid = 12345; private boolean mCreateTask; private ActivityStack mStack; private int mActivityFlags; Loading Loading @@ -175,6 +176,11 @@ class ActivityTestsBase extends SystemServiceTestsBase { return this; } ActivityBuilder setProcessName(String name) { mProcessName = name; return this; } ActivityBuilder setUid(int uid) { mUid = uid; return this; Loading Loading @@ -235,6 +241,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; aInfo.processName = mProcessName; aInfo.packageName = mComponent.getPackageName(); if (mTargetActivity != null) { aInfo.targetActivity = mTargetActivity; Loading Loading @@ -268,7 +275,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { } final WindowProcessController wpc = new WindowProcessController(mService, mService.mContext.getApplicationInfo(), "name", 12345, mService.mContext.getApplicationInfo(), mProcessName, mUid, UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class)); wpc.setThread(mock(IApplicationThread.class)); Loading