summaryrefslogtreecommitdiff
path: root/apct-tests/perftests/core
diff options
context:
space:
mode:
authorRiddle Hsu <riddlehsu@google.com>2019-07-26 21:28:51 -0600
committerRiddle Hsu <riddlehsu@google.com>2019-07-26 21:35:35 +0800
commit5ef56dd6f36f904b1ad916cae54f22ac41759b14 (patch)
tree65dea9f2ad003d5a7f797c9e86ad8b02ec94ff0b /apct-tests/perftests/core
parentcac13d44ab9ced55b6bb13d05993634d9d322487 (diff)
Add performance test for operations of recents activity
Includes startRecentsActivity, startActivityFromRecents, and IRecentsAnimationController.finish. Also make the output stats of manual benchmark customizable. Bug: 131727899 Test: atest RecentsAnimationPerfTest Change-Id: I89a08248b4f215c990640aeb50800759d6dbcf22
Diffstat (limited to 'apct-tests/perftests/core')
-rw-r--r--apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java276
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java2
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java4
3 files changed, 279 insertions, 3 deletions
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
new file mode 100644
index 000000000000..4e2b281da1b4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -0,0 +1,276 @@
+/*
+ * 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.STATS_REPORT_COEFFICIENT_VAR;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_ITERATION;
+import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_MEAN;
+
+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.Activity;
+import android.app.ActivityTaskManager;
+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.perftests.utils.StubActivity;
+import android.util.Pair;
+import android.view.IRecentsAnimationController;
+import android.view.IRecentsAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.WindowManager;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
+import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
+import androidx.test.runner.lifecycle.Stage;
+
+import org.junit.After;
+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 {
+ private static Intent sRecentsIntent;
+
+ @Rule
+ public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+ @Rule
+ public final ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule<>(
+ StubActivity.class, false /* initialTouchMode */, false /* launchActivity */);
+
+ private long mMeasuredTimeNs;
+ private LifecycleListener mLifecycleListener;
+
+ @Parameterized.Parameter(0)
+ public int intervalBetweenOperations;
+
+ @Parameterized.Parameters(name = "interval{0}ms")
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { 0 },
+ { 100 },
+ { 300 },
+ });
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ // Get the permission to invoke startRecentsActivity.
+ sUiAutomation.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) {
+ Assume.assumeNoException(e);
+ }
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ sUiAutomation.dropShellPermissionIdentity();
+ }
+
+ @Before
+ @Override
+ public void setUp() {
+ super.setUp();
+ final Activity testActivity = mActivityRule.launchActivity(null /* intent */);
+ try {
+ mActivityRule.runOnUiThread(() -> testActivity.getWindow()
+ .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON));
+ } catch (Throwable ignored) { }
+ mLifecycleListener = new LifecycleListener(testActivity);
+ ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleListener);
+ }
+
+ @After
+ public void tearDown() {
+ ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(mLifecycleListener);
+ }
+
+ /** Simulate the timing of touch. */
+ private void makeInterval() {
+ SystemClock.sleep(intervalBetweenOperations);
+ }
+
+ /**
+ * <pre>
+ * 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).
+ * </pre>
+ */
+ @Test
+ @ManualBenchmarkTest(
+ warmupDurationNs = TIME_1_S_IN_NS,
+ targetTestDurationNs = TIME_5_S_IN_NS,
+ statsReportFlags =
+ STATS_REPORT_ITERATION | STATS_REPORT_MEAN | STATS_REPORT_COEFFICIENT_VAR)
+ public void testRecentsAnimation() throws Throwable {
+ final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final IActivityTaskManager atm = ActivityTaskManager.getService();
+
+ final ArrayList<Pair<String, Boolean>> 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, Rect homeContentInsets,
+ Rect minimizedHomeBounds) throws RemoteException {
+ final Pair<String, Boolean> 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) {
+ mLifecycleListener.waitForIdleSync(Stage.STOPPED);
+
+ startTime = SystemClock.elapsedRealtimeNanos();
+ atm.startActivityFromRecents(testActivityTaskId, null /* options */);
+ final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
+ mMeasuredTimeNs += elapsedTimeNs;
+ state.addExtraResult("startFromRecents", elapsedTimeNs);
+
+ mLifecycleListener.waitForIdleSync(Stage.RESUMED);
+ }
+
+ makeInterval();
+ recentsSemaphore.release();
+ }
+
+ @Override
+ public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException {
+ Assume.assumeNoException(
+ new AssertionError("onAnimationCanceled should not be called"));
+ }
+ };
+
+ while (state.keepRunning(mMeasuredTimeNs)) {
+ Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS));
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+ final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime;
+ mMeasuredTimeNs += elapsedTimeNsOfStart;
+ state.addExtraResult("start", elapsedTimeNsOfStart);
+ }
+
+ // Ensure the last round of animation callback is done.
+ recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS);
+ recentsSemaphore.release();
+ }
+
+ private static class LifecycleListener implements ActivityLifecycleCallback {
+ private final Activity mTargetActivity;
+ private Stage mWaitingStage;
+ private Stage mReceivedStage;
+
+ LifecycleListener(Activity activity) {
+ mTargetActivity = activity;
+ }
+
+ void waitForIdleSync(Stage state) {
+ synchronized (this) {
+ if (state != mReceivedStage) {
+ mWaitingStage = state;
+ try {
+ wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS));
+ } catch (InterruptedException impossible) { }
+ }
+ mWaitingStage = mReceivedStage = null;
+ }
+ getInstrumentation().waitForIdleSync();
+ }
+
+ @Override
+ public void onActivityLifecycleChanged(Activity activity, Stage stage) {
+ if (mTargetActivity != activity) {
+ return;
+ }
+
+ synchronized (this) {
+ mReceivedStage = stage;
+ if (mWaitingStage == mReceivedStage) {
+ notifyAll();
+ }
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
index a95186916cea..27790e649a26 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java
@@ -60,7 +60,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
}
@Test
- @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION)
+ @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS)
public void testAddRemoveWindow() throws Throwable {
new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
}
diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
index b2c61688ef59..4864da4b0195 100644
--- a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java
@@ -25,8 +25,8 @@ import org.junit.Before;
public class WindowManagerPerfTestBase {
static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation();
static final long NANOS_PER_S = 1000L * 1000 * 1000;
- static final long WARMUP_DURATION = 1 * NANOS_PER_S;
- static final long TEST_DURATION = 5 * NANOS_PER_S;
+ static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+ static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
@Before
public void setUp() {