Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab819241 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add CUJs for sysui e2e shade perf tests" into main

parents d1a80216 485411cb
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -416,8 +416,16 @@ public class Cuj {
     */
    public static final int CUJ_WEAR_NOTIFICATION_TRAY_OPEN = 137;

    /**
     * Tracking when notification shade window gets moved between displays
     *
     * <p>Tracking starts when the notification shade starts to move to a new display, and ends
     * when the notification shade is fully expanded in the new display.
     */
    public static final int CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE = 138;

    // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
    @VisibleForTesting static final int LAST_CUJ = CUJ_WEAR_NOTIFICATION_TRAY_OPEN;
    @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE;

    /** @hide */
    @IntDef({
@@ -546,8 +554,8 @@ public class Cuj {
            CUJ_WEAR_CAROUSEL_FLING_JANK,
            CUJ_WEAR_CAROUSEL_SWIPE_JANK,
            CUJ_WEAR_QSS_TRAY_OPEN,
            CUJ_WEAR_NOTIFICATION_TRAY_OPEN

            CUJ_WEAR_NOTIFICATION_TRAY_OPEN,
            CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CujType {}
@@ -687,6 +695,7 @@ public class Cuj {
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_CAROUSEL_SWIPE_JANK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_CAROUSEL_SWIPE_JANK;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_QSS_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_QSS_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_WEAR_NOTIFICATION_TRAY_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WEAR_NOTIFICATION_TRAY_OPEN;
        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE;
    }

    private Cuj() {
@@ -957,6 +966,8 @@ public class Cuj {
                return "WEAR_QSS_TRAY_OPEN";
            case CUJ_WEAR_NOTIFICATION_TRAY_OPEN:
                return "WEAR_NOTIFICATION_TRAY_OPEN";
            case CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE:
                return "DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE";
        }
        return "UNKNOWN";
    }
+80 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import com.android.internal.logging.latencyTracker
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.common.ui.view.fakeChoreographerUtils
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
@@ -30,6 +31,7 @@ import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
@@ -38,14 +40,16 @@ import org.mockito.kotlin.any
@SmallTest
@RunWith(AndroidJUnit4::class)
@android.platform.test.annotations.EnabledOnRavenwood
class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
class ShadeDisplayChangePerformanceTrackerTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val configurationRepository = kosmos.fakeConfigurationRepository
    private val latencyTracker = kosmos.latencyTracker
    private val jankMonitor = kosmos.interactionJankMonitor
    private val testScope = kosmos.testScope
    private val choreographerUtils = kosmos.fakeChoreographerUtils
    private val shadeTestUtil = kosmos.shadeTestUtil

    private val underTest = kosmos.shadeDisplayChangeLatencyTracker
    private val underTest = kosmos.shadeDisplayChangePerformanceTracker

    @Test
    fun onShadeDisplayChanging_afterMovedToDisplayAndDoFrameCompleted_atomReported() =
@@ -61,6 +65,28 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            verify(latencyTracker).onActionEnd(any())
        }

    @Test
    fun onShadeDisplayChanging_jankCujBegins() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())
        }

    @Test
    fun onShadeDisplayChanging_afterShadeExpansion_jankCujEnd() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor).end(anyInt())
        }

    @Test
    fun onChange_doFrameTimesOut_previousCancelled() =
        testScope.runTest {
@@ -87,10 +113,25 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            advanceTimeBy(100.seconds)

            verify(latencyTracker).onActionCancel(any())
            verify(jankMonitor).cancel(anyInt())
        }

    @Test
    fun onChange_whilePreviousWasInProgress_previousCancelledAndNewStarted() =
    fun onChange_onShadeExpandedTimesOut_cancelled() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            advanceTimeBy(100.seconds)

            verify(jankMonitor).cancel(anyInt())
        }

    @Test
    fun onChange_whilePreviousWasInProgress_previousLatencyRecordCancelledAndNewStarted() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

@@ -103,7 +144,20 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
        }

    @Test
    fun onChange_multiple_multipleReported() =
    fun onChange_whilePreviousWasInProgress_previousJankRecordCancelledAndNewStarted() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)

            verify(jankMonitor).begin(any(), anyInt())

            underTest.onShadeDisplayChanging(2)

            verify(jankMonitor).cancel(anyInt())
            verify(jankMonitor, times(2)).begin(any(), anyInt())
        }

    @Test
    fun onChange_multiple_multipleLatencyRecordReported() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)
            verify(latencyTracker).onActionStart(any())
@@ -122,6 +176,28 @@ class ShadeDisplayChangeLatencyTrackerTest : SysuiTestCase() {
            verify(latencyTracker, times(2)).onActionEnd(any())
        }

    @Test
    fun onChange_multiple_multipleJankRecordReported() =
        testScope.runTest {
            underTest.onShadeDisplayChanging(1)
            verify(jankMonitor).begin(any(), anyInt())

            sendOnMovedToDisplay(1)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor).end(anyInt())

            underTest.onShadeDisplayChanging(0)

            sendOnMovedToDisplay(0)
            choreographerUtils.completeDoFrame()
            shadeTestUtil.setShadeExpansion(1f)

            verify(jankMonitor, times(2)).begin(any(), anyInt())
            verify(jankMonitor, times(2)).end(anyInt())
        }

    private fun sendOnMovedToDisplay(displayId: Int) {
        configurationRepository.onMovedToDisplay(displayId)
    }
+3 −3
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
    private val positionRepository = kosmos.fakeShadeDisplaysRepository
    private val shadeContext = kosmos.mockedWindowContext
    private val resources = kosmos.mockResources
    private val latencyTracker = kosmos.mockedShadeDisplayChangeLatencyTracker
    private val performanceTracker = kosmos.mockedShadeDisplayChangePerformanceTracker
    private val configuration = mock<Configuration>()
    private val display = mock<Display>()
    private val activeNotificationRepository = kosmos.activeNotificationListRepository
@@ -104,14 +104,14 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        }

    @Test
    fun start_shadeInWrongPosition_logsStartToLatencyTracker() =
    fun start_shadeInWrongPosition_logsStartToPerformanceTracker() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setPendingDisplayId(1)

            underTest.start()

            verify(latencyTracker).onShadeDisplayChanging(eq(1))
            verify(performanceTracker).onShadeDisplayChanging(eq(1))
        }

    @Test
+22 −9
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@
package com.android.systemui.shade

import android.util.Log
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.util.LatencyTracker
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.domain.interactor.ShadeDisplaysWaitInteractor
import java.util.concurrent.CancellationException
@@ -30,21 +33,23 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout

/**
 * Tracks the time it takes to move the shade from one display to another.
 * - The start event is when [ShadeDisplaysRepository] propagates the new display ID.
 * - The end event is one frame after the shade configuration controller receives a new
 *   configuration change.
 *
 * Note that even in the unlikely case the configuration of the new display is the same,
 * onConfigurationChange is called anyway as is is triggered by
 * Records the performance of moving the shade from one display to another - tracking both the
 * latency and jank involved in the process.
 * - Recording starts when [ShadeDisplaysRepository] propagates the new display ID.
 * - Latency tracking ends one frame after the shade configuration controller receives a new
 *   configuration change. (Note: even if the configuration of the new display is the same,
 *   onConfigurationChange is called anyway as it is triggered by
 *   [NotificationShadeWindowView.onMovedToDisplay].
 * - Jank tracking ends after the shade window is fully expanded.
 */
@SysUISingleton
class ShadeDisplayChangeLatencyTracker
class ShadeDisplayChangePerformanceTracker
@Inject
constructor(
    private val latencyTracker: LatencyTracker,
    private val shadeRootView: WindowRootView,
    @Background private val bgScope: CoroutineScope,
    private val jankMonitor: InteractionJankMonitor,
    private val waitInteractor: ShadeDisplaysWaitInteractor,
) {

@@ -69,10 +74,13 @@ constructor(

    private suspend fun onShadeDisplayChangingAsync(displayId: Int) {
        try {
            jankMonitor.begin(shadeRootView, CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
            latencyTracker.onActionStart(SHADE_MOVE_ACTION)
            waitForOnMovedToDisplayDispatchedToView(displayId)
            waitUntilNextDoFrameDone(displayId)
            latencyTracker.onActionEnd(SHADE_MOVE_ACTION)
            waitForShadeExpanded()
            jankMonitor.end(CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
        } catch (e: Exception) {
            val reason =
                when (e) {
@@ -84,6 +92,7 @@ constructor(
                }
            Log.e(TAG, reason, e)
            latencyTracker.onActionCancel(SHADE_MOVE_ACTION)
            jankMonitor.cancel(CUJ_DESKTOP_MODE_SHADE_WINDOW_DISPLAY_CHANGE)
        }
    }

@@ -97,6 +106,10 @@ constructor(
        withTimeout(TIMEOUT) { waitInteractor.waitForNextDoFrameDone(newDisplayId, TAG) }
    }

    private suspend fun waitForShadeExpanded() {
        withTimeout(TIMEOUT) { waitInteractor.waitForShadeExpanded(TAG) }
    }

    private companion object {
        const val TAG = "ShadeDisplayLatency"
        val TIMEOUT = 3.seconds
+3 −3
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.shade.ShadeDisplayChangeLatencyTracker
import com.android.systemui.shade.ShadeDisplayChangePerformanceTracker
import com.android.systemui.shade.ShadeDisplayLog
import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
import com.android.systemui.shade.ShadeTraceLogger.t
@@ -72,7 +72,7 @@ constructor(
    @ShadeDisplayAware private val shadeContext: WindowContext,
    @Background private val bgScope: CoroutineScope,
    @Main private val mainThreadContext: CoroutineContext,
    private val shadeDisplayChangeLatencyTracker: ShadeDisplayChangeLatencyTracker,
    private val shadeDisplayChangePerformanceTracker: ShadeDisplayChangePerformanceTracker,
    private val shadeExpandedInteractor: ShadeExpandedStateInteractor,
    private val shadeExpansionIntent: ShadeExpansionIntent,
    private val activeNotificationsInteractor: ActiveNotificationsInteractor,
@@ -142,7 +142,7 @@ constructor(
            withContext(mainThreadContext) {
                traceReparenting {
                    collapseAndExpandShadeIfNeeded(destinationId) {
                        shadeDisplayChangeLatencyTracker.onShadeDisplayChanging(destinationId)
                        shadeDisplayChangePerformanceTracker.onShadeDisplayChanging(destinationId)
                        reparentToDisplayId(id = destinationId)
                    }
                    checkContextDisplayMatchesExpected(destinationId)
Loading