Loading services/core/java/com/android/server/wm/ActivityMetricsLogger.java +23 −7 Original line number Original line Diff line number Diff line Loading @@ -187,9 +187,24 @@ class ActivityMetricsLogger { private int startingWindowDelayMs = INVALID_DELAY; private int startingWindowDelayMs = INVALID_DELAY; private int bindApplicationDelayMs = INVALID_DELAY; private int bindApplicationDelayMs = INVALID_DELAY; private int reason = APP_TRANSITION_TIMEOUT; private int reason = APP_TRANSITION_TIMEOUT; private boolean loggedWindowsDrawn; private int numUndrawnActivities; private boolean loggedStartingWindowDrawn; private boolean loggedStartingWindowDrawn; private boolean launchTraceActive; private boolean launchTraceActive; /** * Remembers the latest launched activity to represent the final transition. This also * increments the number of activities that should be drawn, so a consecutive launching * sequence can be coalesced as one event. */ void setLatestLaunchedActivity(ActivityRecord r) { if (launchedActivity == r) { return; } launchedActivity = r; if (!r.noDisplay) { numUndrawnActivities++; } } } } final class WindowingModeTransitionInfoSnapshot { final class WindowingModeTransitionInfoSnapshot { Loading Loading @@ -400,7 +415,7 @@ class ActivityMetricsLogger { // the other attributes. // the other attributes. // Coalesce multiple (trampoline) activities from a single sequence together. // Coalesce multiple (trampoline) activities from a single sequence together. info.launchedActivity = launchedActivity; info.setLatestLaunchedActivity(launchedActivity); return; return; } } Loading @@ -422,7 +437,7 @@ class ActivityMetricsLogger { // A new launch sequence [with the windowingMode] has begun. // A new launch sequence [with the windowingMode] has begun. // Start tracking it. // Start tracking it. final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo(); final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo(); newInfo.launchedActivity = launchedActivity; newInfo.setLatestLaunchedActivity(launchedActivity); newInfo.currentTransitionProcessRunning = processRunning; newInfo.currentTransitionProcessRunning = processRunning; newInfo.startResult = resultCode; newInfo.startResult = resultCode; mWindowingModeTransitionInfo.put(windowingMode, newInfo); mWindowingModeTransitionInfo.put(windowingMode, newInfo); Loading @@ -448,11 +463,11 @@ class ActivityMetricsLogger { if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); if (info == null || info.loggedWindowsDrawn) { if (info == null || info.numUndrawnActivities == 0) { return null; return null; } } info.windowsDrawnDelayMs = calculateDelay(timestampNs); info.windowsDrawnDelayMs = calculateDelay(timestampNs); info.loggedWindowsDrawn = true; info.numUndrawnActivities--; final WindowingModeTransitionInfoSnapshot infoSnapshot = final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { if (allWindowsDrawn() && mLoggedTransitionStarting) { Loading Loading @@ -594,9 +609,10 @@ class ActivityMetricsLogger { } } } } private boolean allWindowsDrawn() { @VisibleForTesting boolean allWindowsDrawn() { for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) { for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) { if (!mWindowingModeTransitionInfo.valueAt(index).loggedWindowsDrawn) { if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) { return false; return false; } } } } Loading services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +68 −78 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,6 @@ package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading Loading @@ -63,10 +61,8 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private ActivityMetricsLaunchObserver mLaunchObserver; private ActivityMetricsLaunchObserver mLaunchObserver; private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; private ActivityStack mStack; private ActivityRecord mTrampolineActivity; private TaskRecord mTask; private ActivityRecord mTopActivity; private ActivityRecord mActivityRecord; private ActivityRecord mActivityRecordTrampoline; @Before @Before public void setUpAMLO() { public void setUpAMLO() { Loading @@ -80,15 +76,10 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // This seems to be the easiest way to create an ActivityRecord. // This seems to be the easiest way to create an ActivityRecord. mStack = new StackBuilder(mRootActivityContainer) mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build(); .setActivityType(ACTIVITY_TYPE_STANDARD) mTopActivity = new ActivityBuilder(mService) .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setTask(mTrampolineActivity.getTaskRecord()) .setOnTop(true) .setCreateActivity(true) .build(); .build(); mTask = mStack.topTask(); mActivityRecord = mTask.getTopActivity(); mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build(); } } @After @After Loading Loading @@ -123,8 +114,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5))); return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5))); } } @Test private void onIntentStarted() { public void testOnIntentStarted() throws Exception { Intent intent = new Intent("action 1"); Intent intent = new Intent("action 1"); mActivityMetricsLogger.notifyActivityLaunching(intent); mActivityMetricsLogger.notifyActivityLaunching(intent); Loading @@ -134,123 +124,123 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } } @Test @Test public void testOnIntentFailed() throws Exception { public void testOnIntentFailed() { testOnIntentStarted(); onIntentStarted(); ActivityRecord activityRecord = null; // Bringing an intent that's already running 'to front' is not considered // Bringing an intent that's already running 'to front' is not considered // as an ACTIVITY_LAUNCHED state transition. // as an ACTIVITY_LAUNCHED state transition. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, activityRecord); null /* launchedActivity */); verifyAsync(mLaunchObserver).onIntentFailed(); verifyAsync(mLaunchObserver).onIntentFailed(); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test private void onActivityLaunched() { public void testOnActivityLaunched() throws Exception { onIntentStarted(); testOnIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityRecord); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchFinished() throws Exception { public void testOnActivityLaunchFinished() { testOnActivityLaunched(); onActivityLaunched(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(), notifyWindowsDrawn(mTopActivity); SystemClock.elapsedRealtimeNanos()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchCancelled() throws Exception { public void testOnActivityLaunchCancelled() { testOnActivityLaunched(); onActivityLaunched(); mActivityRecord.mDrawn = true; mTopActivity.mDrawn = true; // Cannot time already-visible activities. // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord); mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity)); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnReportFullyDrawn() throws Exception { public void testOnReportFullyDrawn() { testOnActivityLaunched(); onActivityLaunched(); mActivityMetricsLogger.logAppTransitionReportedDrawn(mActivityRecord, false); mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mActivityRecord), anyLong()); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test private void onActivityLaunchedTrampoline() { public void testOnActivityLaunchedTrampoline() throws Exception { onIntentStarted(); testOnIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityRecord); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); // A second, distinct, activity launch is coalesced into the the current app launch sequence // A second, distinct, activity launch is coalesced into the the current app launch sequence mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); mActivityRecordTrampoline); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } private void notifyWindowsDrawn(ActivityRecord r) { mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(), SystemClock.elapsedRealtimeNanos()); } @Test @Test public void testOnActivityLaunchFinishedTrampoline() throws Exception { public void testOnActivityLaunchFinishedTrampoline() { testOnActivityLaunchedTrampoline(); onActivityLaunchedTrampoline(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(), notifyWindowsDrawn(mTrampolineActivity); SystemClock.elapsedRealtimeNanos()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline), assertWithMessage("Trampoline activity is drawn but the top activity is not yet") .that(mActivityMetricsLogger.allWindowsDrawn()).isFalse(); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity), anyLong()); anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchCancelledTrampoline() throws Exception { public void testOnActivityLaunchCancelledTrampoline() { testOnActivityLaunchedTrampoline(); onActivityLaunchedTrampoline(); mActivityRecordTrampoline.mDrawn = true; mTrampolineActivity.mDrawn = true; // Cannot time already-visible activities. // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity); mActivityRecordTrampoline); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity)); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testActivityRecordProtoIsNotTooBig() throws Exception { public void testActivityRecordProtoIsNotTooBig() { // The ActivityRecordProto must not be too big, otherwise converting it at runtime // The ActivityRecordProto must not be too big, otherwise converting it at runtime // will become prohibitively expensive. // will become prohibitively expensive. assertWithMessage("mActivityRecord: %s", mActivityRecord). assertWithMessage("mTopActivity: %s", mTopActivity) that(activityRecordToProto(mActivityRecord).length). .that(activityRecordToProto(mTopActivity).length) isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline). assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity) that(activityRecordToProto(mActivityRecordTrampoline).length). .that(activityRecordToProto(mTrampolineActivity).length) isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); } } } } Loading
services/core/java/com/android/server/wm/ActivityMetricsLogger.java +23 −7 Original line number Original line Diff line number Diff line Loading @@ -187,9 +187,24 @@ class ActivityMetricsLogger { private int startingWindowDelayMs = INVALID_DELAY; private int startingWindowDelayMs = INVALID_DELAY; private int bindApplicationDelayMs = INVALID_DELAY; private int bindApplicationDelayMs = INVALID_DELAY; private int reason = APP_TRANSITION_TIMEOUT; private int reason = APP_TRANSITION_TIMEOUT; private boolean loggedWindowsDrawn; private int numUndrawnActivities; private boolean loggedStartingWindowDrawn; private boolean loggedStartingWindowDrawn; private boolean launchTraceActive; private boolean launchTraceActive; /** * Remembers the latest launched activity to represent the final transition. This also * increments the number of activities that should be drawn, so a consecutive launching * sequence can be coalesced as one event. */ void setLatestLaunchedActivity(ActivityRecord r) { if (launchedActivity == r) { return; } launchedActivity = r; if (!r.noDisplay) { numUndrawnActivities++; } } } } final class WindowingModeTransitionInfoSnapshot { final class WindowingModeTransitionInfoSnapshot { Loading Loading @@ -400,7 +415,7 @@ class ActivityMetricsLogger { // the other attributes. // the other attributes. // Coalesce multiple (trampoline) activities from a single sequence together. // Coalesce multiple (trampoline) activities from a single sequence together. info.launchedActivity = launchedActivity; info.setLatestLaunchedActivity(launchedActivity); return; return; } } Loading @@ -422,7 +437,7 @@ class ActivityMetricsLogger { // A new launch sequence [with the windowingMode] has begun. // A new launch sequence [with the windowingMode] has begun. // Start tracking it. // Start tracking it. final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo(); final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo(); newInfo.launchedActivity = launchedActivity; newInfo.setLatestLaunchedActivity(launchedActivity); newInfo.currentTransitionProcessRunning = processRunning; newInfo.currentTransitionProcessRunning = processRunning; newInfo.startResult = resultCode; newInfo.startResult = resultCode; mWindowingModeTransitionInfo.put(windowingMode, newInfo); mWindowingModeTransitionInfo.put(windowingMode, newInfo); Loading @@ -448,11 +463,11 @@ class ActivityMetricsLogger { if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode); if (info == null || info.loggedWindowsDrawn) { if (info == null || info.numUndrawnActivities == 0) { return null; return null; } } info.windowsDrawnDelayMs = calculateDelay(timestampNs); info.windowsDrawnDelayMs = calculateDelay(timestampNs); info.loggedWindowsDrawn = true; info.numUndrawnActivities--; final WindowingModeTransitionInfoSnapshot infoSnapshot = final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); new WindowingModeTransitionInfoSnapshot(info); if (allWindowsDrawn() && mLoggedTransitionStarting) { if (allWindowsDrawn() && mLoggedTransitionStarting) { Loading Loading @@ -594,9 +609,10 @@ class ActivityMetricsLogger { } } } } private boolean allWindowsDrawn() { @VisibleForTesting boolean allWindowsDrawn() { for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) { for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) { if (!mWindowingModeTransitionInfo.valueAt(index).loggedWindowsDrawn) { if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) { return false; return false; } } } } Loading
services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +68 −78 Original line number Original line Diff line number Diff line Loading @@ -18,8 +18,6 @@ package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading Loading @@ -63,10 +61,8 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { private ActivityMetricsLaunchObserver mLaunchObserver; private ActivityMetricsLaunchObserver mLaunchObserver; private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry; private ActivityStack mStack; private ActivityRecord mTrampolineActivity; private TaskRecord mTask; private ActivityRecord mTopActivity; private ActivityRecord mActivityRecord; private ActivityRecord mActivityRecordTrampoline; @Before @Before public void setUpAMLO() { public void setUpAMLO() { Loading @@ -80,15 +76,10 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful. // This seems to be the easiest way to create an ActivityRecord. // This seems to be the easiest way to create an ActivityRecord. mStack = new StackBuilder(mRootActivityContainer) mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build(); .setActivityType(ACTIVITY_TYPE_STANDARD) mTopActivity = new ActivityBuilder(mService) .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setTask(mTrampolineActivity.getTaskRecord()) .setOnTop(true) .setCreateActivity(true) .build(); .build(); mTask = mStack.topTask(); mActivityRecord = mTask.getTopActivity(); mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build(); } } @After @After Loading Loading @@ -123,8 +114,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5))); return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5))); } } @Test private void onIntentStarted() { public void testOnIntentStarted() throws Exception { Intent intent = new Intent("action 1"); Intent intent = new Intent("action 1"); mActivityMetricsLogger.notifyActivityLaunching(intent); mActivityMetricsLogger.notifyActivityLaunching(intent); Loading @@ -134,123 +124,123 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { } } @Test @Test public void testOnIntentFailed() throws Exception { public void testOnIntentFailed() { testOnIntentStarted(); onIntentStarted(); ActivityRecord activityRecord = null; // Bringing an intent that's already running 'to front' is not considered // Bringing an intent that's already running 'to front' is not considered // as an ACTIVITY_LAUNCHED state transition. // as an ACTIVITY_LAUNCHED state transition. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, activityRecord); null /* launchedActivity */); verifyAsync(mLaunchObserver).onIntentFailed(); verifyAsync(mLaunchObserver).onIntentFailed(); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test private void onActivityLaunched() { public void testOnActivityLaunched() throws Exception { onIntentStarted(); testOnIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityRecord); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchFinished() throws Exception { public void testOnActivityLaunchFinished() { testOnActivityLaunched(); onActivityLaunched(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(), notifyWindowsDrawn(mTopActivity); SystemClock.elapsedRealtimeNanos()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord), anyLong()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchCancelled() throws Exception { public void testOnActivityLaunchCancelled() { testOnActivityLaunched(); onActivityLaunched(); mActivityRecord.mDrawn = true; mTopActivity.mDrawn = true; // Cannot time already-visible activities. // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord); mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity)); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnReportFullyDrawn() throws Exception { public void testOnReportFullyDrawn() { testOnActivityLaunched(); onActivityLaunched(); mActivityMetricsLogger.logAppTransitionReportedDrawn(mActivityRecord, false); mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mActivityRecord), anyLong()); verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test private void onActivityLaunchedTrampoline() { public void testOnActivityLaunchedTrampoline() throws Exception { onIntentStarted(); testOnIntentStarted(); mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity); mActivityRecord); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt()); verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt()); // A second, distinct, activity launch is coalesced into the the current app launch sequence // A second, distinct, activity launch is coalesced into the the current app launch sequence mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity); mActivityRecordTrampoline); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } private void notifyWindowsDrawn(ActivityRecord r) { mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(), SystemClock.elapsedRealtimeNanos()); } @Test @Test public void testOnActivityLaunchFinishedTrampoline() throws Exception { public void testOnActivityLaunchFinishedTrampoline() { testOnActivityLaunchedTrampoline(); onActivityLaunchedTrampoline(); mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(), SystemClock.elapsedRealtimeNanos()); SystemClock.elapsedRealtimeNanos()); mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(), notifyWindowsDrawn(mTrampolineActivity); SystemClock.elapsedRealtimeNanos()); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline), assertWithMessage("Trampoline activity is drawn but the top activity is not yet") .that(mActivityMetricsLogger.allWindowsDrawn()).isFalse(); notifyWindowsDrawn(mTopActivity); verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity), anyLong()); anyLong()); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testOnActivityLaunchCancelledTrampoline() throws Exception { public void testOnActivityLaunchCancelledTrampoline() { testOnActivityLaunchedTrampoline(); onActivityLaunchedTrampoline(); mActivityRecordTrampoline.mDrawn = true; mTrampolineActivity.mDrawn = true; // Cannot time already-visible activities. // Cannot time already-visible activities. mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity); mActivityRecordTrampoline); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline)); verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity)); verifyNoMoreInteractions(mLaunchObserver); verifyNoMoreInteractions(mLaunchObserver); } } @Test @Test public void testActivityRecordProtoIsNotTooBig() throws Exception { public void testActivityRecordProtoIsNotTooBig() { // The ActivityRecordProto must not be too big, otherwise converting it at runtime // The ActivityRecordProto must not be too big, otherwise converting it at runtime // will become prohibitively expensive. // will become prohibitively expensive. assertWithMessage("mActivityRecord: %s", mActivityRecord). assertWithMessage("mTopActivity: %s", mTopActivity) that(activityRecordToProto(mActivityRecord).length). .that(activityRecordToProto(mTopActivity).length) isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline). assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity) that(activityRecordToProto(mActivityRecordTrampoline).length). .that(activityRecordToProto(mTrampolineActivity).length) isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE); } } } }