All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.wm.RecentsAnimationPerfTest Maven / Gradle / Ivy

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.wm;

import static android.perftests.utils.ManualBenchmarkState.StatsReport;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static org.hamcrest.core.AnyOf.anyOf;
import static org.hamcrest.core.Is.is;

import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.window.TaskSnapshot;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.SystemClock;
import android.perftests.utils.ManualBenchmarkState;
import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
import android.perftests.utils.PerfManualStatusReporter;
import android.util.Pair;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
import android.view.RemoteAnimationTarget;

import androidx.test.filters.LargeTest;
import androidx.test.runner.lifecycle.Stage;

import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

@RunWith(Parameterized.class)
@LargeTest
public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
        implements ManualBenchmarkState.CustomizedIterationListener {
    private static Intent sRecentsIntent;

    @Rule
    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();

    @Rule
    public final PerfTestActivityRule mActivityRule =
            new PerfTestActivityRule(true /* launchActivity */);

    private long mMeasuredTimeNs;

    /**
     * Used to skip each test method if there is error. It cannot be raised in static setup because
     * that will break the amount of target method count.
     */
    private static Exception sSetUpClassException;

    @Parameterized.Parameter(0)
    public int intervalBetweenOperations;

    @Parameterized.Parameters(name = "interval{0}ms")
    public static Collection getParameters() {
        return Arrays.asList(new Object[][] {
                { 0 },
                { 100 },
                { 300 },
        });
    }

    @BeforeClass
    public static void setUpClass() {
        // Get the permission to invoke startRecentsActivity.
        getUiAutomation().adoptShellPermissionIdentity();

        final Context context = getInstrumentation().getContext();
        final PackageManager pm = context.getPackageManager();
        final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>());

        try {
            final ComponentName recentsComponent =
                    ComponentName.unflattenFromString(context.getResources().getString(
                            com.android.internal.R.string.config_recentsComponentName));
            final int enabledState = pm.getComponentEnabledSetting(recentsComponent);
            Assume.assumeThat(enabledState, anyOf(
                    is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
                    is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)));

            final boolean homeIsRecents =
                    recentsComponent.getPackageName().equals(defaultHome.getPackageName());
            sRecentsIntent =
                    new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent);
        } catch (Exception e) {
            sSetUpClassException = e;
        }
    }

    @AfterClass
    public static void tearDownClass() {
        sSetUpClassException = null;
        try {
            // Recents activity may stop app switches. Restore the state to avoid affecting
            // the next test.
            ActivityManager.resumeAppSwitches();
        } catch (RemoteException ignored) {
        }
        getUiAutomation().dropShellPermissionIdentity();
    }

    @Before
    public void setUp() {
        Assume.assumeNoException(sSetUpClassException);
    }

    /** Simulate the timing of touch. */
    private void makeInterval() {
        SystemClock.sleep(intervalBetweenOperations);
    }

    /**
     * 
     * Steps:
     * (1) Start recents activity (only make it visible).
     * (2) Finish animation, take turns to execute (a), (b).
     *     (a) Move recents activity to top.
     * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP})
     *         Move test app to top by startActivityFromRecents.
     *     (b) Cancel (it is similar to swipe a little distance and give up to enter recents).
     * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION})
     * (3) Loop (1).
     * 
*/ @Test @ManualBenchmarkTest( warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS, statsReport = @StatsReport(flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN | StatsReport.FLAG_COEFFICIENT_VAR)) public void testRecentsAnimation() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); state.setCustomizedIterations(getProfilingIterations(), this); final IActivityTaskManager atm = ActivityTaskManager.getService(); final ArrayList> finishCases = new ArrayList<>(); // Real launch the recents activity. finishCases.add(new Pair<>("finishMoveToTop", true)); // Return to the original top. finishCases.add(new Pair<>("finishCancel", false)); // Ensure startRecentsActivity won't be called before finishing the animation. final Semaphore recentsSemaphore = new Semaphore(1); final int testActivityTaskId = mActivityRule.getActivity().getTaskId(); final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() { int mIteration; @Override public void onAnimationStart(IRecentsAnimationController controller, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException { final Pair finishCase = finishCases.get(mIteration++ % 2); final boolean moveRecentsToTop = finishCase.second; makeInterval(); long startTime = SystemClock.elapsedRealtimeNanos(); controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */); final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfFinish; state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish); if (moveRecentsToTop) { mActivityRule.waitForIdleSync(Stage.STOPPED); startTime = SystemClock.elapsedRealtimeNanos(); atm.startActivityFromRecents(testActivityTaskId, null /* options */); final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNs; state.addExtraResult("startFromRecents", elapsedTimeNs); mActivityRule.waitForIdleSync(Stage.RESUMED); } makeInterval(); recentsSemaphore.release(); } @Override public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException { Assume.assumeNoException( new AssertionError("onAnimationCanceled should not be called")); } @Override public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException { /* no-op */ } }; recentsSemaphore.tryAcquire(); while (state.keepRunning(mMeasuredTimeNs)) { mMeasuredTimeNs = 0; final long startTime = SystemClock.elapsedRealtimeNanos(); atm.startRecentsActivity(sRecentsIntent, 0 /* eventTime */, anim); final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfStart; state.addExtraResult("start", elapsedTimeNsOfStart); // Ensure the animation callback is done. Assume.assumeTrue(recentsSemaphore.tryAcquire( sIsProfilingMethod() ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); } } @Override public void onStart(int iteration) { startProfiling(RecentsAnimationPerfTest.class.getSimpleName() + "_interval_" + intervalBetweenOperations + "_MethodTracing_" + iteration + ".trace"); } @Override public void onFinished(int iteration) { stopProfiling(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy