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

Commit 69a9eb0a authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Eliminate non interested parts of content capture perf test

The ActivityTestRule#launchActivity uses startActivitySync, that
will wait until the enter animation is finished. So the metrics
are usually dominated by the animation duration. And because the
test rapidly loops launch and finish, the animation style may be
different. Then the result may not be meaningful.

Because the original purpose of the test is to ensure the frame time,
the timestamp at CALLBACK_COMMIT is more accurate. Also skip the
the animation so the test can run faster about 80%.

Bug: 258883870
Test: atest android.view.contentcapture.LoginTest
Change-Id: I529672e7a60bca8420e96d6c900d95848f94108e
parent b29e4dc3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

    <application>
        <uses-library android:name="android.test.runner" />
        <activity android:name="android.perftests.utils.PerfTestActivity"
                android:exported="true" />
        <activity android:name="android.view.contentcapture.CustomTestActivity"
                android:exported="true">
        </activity>
+34 −17
Original line number Diff line number Diff line
@@ -22,18 +22,20 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat

import static com.android.compatibility.common.util.ShellUtils.runShellCommand;

import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
import android.content.ContentCaptureOptions;
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
import android.os.UserHandle;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.PerfTestActivity;
import android.provider.Settings;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.test.rule.ActivityTestRule;

import com.android.compatibility.common.util.ActivitiesWatcher;
import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
@@ -53,18 +55,18 @@ import org.junit.runners.model.Statement;
public abstract class AbstractContentCapturePerfTestCase {

    private static final String TAG = AbstractContentCapturePerfTestCase.class.getSimpleName();
    private static final long GENERIC_TIMEOUT_MS = 10_000;
    protected static final long GENERIC_TIMEOUT_MS = 5_000;

    private static int sOriginalStayOnWhilePluggedIn;
    private static Context sContext = getInstrumentation().getTargetContext();
    protected static final Instrumentation sInstrumentation = getInstrumentation();
    protected static final Context sContext = sInstrumentation.getTargetContext();

    protected ActivitiesWatcher mActivitiesWatcher;

    private MyContentCaptureService.ServiceWatcher mServiceWatcher;
    /** A simple activity as the task root to reduce the noise of pause and animation time. */
    protected Activity mEntryActivity;

    @Rule
    public ActivityTestRule<CustomTestActivity> mActivityRule =
            new ActivityTestRule<>(CustomTestActivity.class, false, false);
    private MyContentCaptureService.ServiceWatcher mServiceWatcher;

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@@ -220,6 +222,17 @@ public abstract class AbstractContentCapturePerfTestCase {
        }
    }

    @Before
    public void setUp() {
        mEntryActivity = sInstrumentation.startActivitySync(
                PerfTestActivity.createLaunchIntent(sInstrumentation.getContext()));
    }

    @After
    public void tearDown() {
        mEntryActivity.finishAndRemoveTask();
    }

    /**
     * Sets {@link MyContentCaptureService} as the service for the current user and waits until
     * its created, then add the perf test package into allow list.
@@ -248,20 +261,24 @@ public abstract class AbstractContentCapturePerfTestCase {
    }

    /**
     * Launch test activity with give layout and parameter
     * Returns the intent which will launch CustomTestActivity.
     */
    protected CustomTestActivity launchActivity(int layoutId, int numViews) {
        final Intent intent = new Intent(sContext, CustomTestActivity.class);
    protected Intent getLaunchIntent(int layoutId, int numViews) {
        final Intent intent = new Intent(sContext, CustomTestActivity.class)
                // Use NEW_TASK because the context is not activity. It is still in the same task
                // of PerfTestActivity because of the same task affinity. Use NO_ANIMATION because
                // this test focuses on launch time instead of animation duration.
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
        intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
        intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
        return mActivityRule.launchActivity(intent);
        return intent;
    }

    protected void finishActivity() {
        try {
            mActivityRule.finishActivity();
        } catch (IllegalStateException e) {
            // no op
        }
    /**
     * Launch test activity with give layout and parameter
     */
    protected CustomTestActivity launchActivity(int layoutId, int numViews) {
        final Intent intent = getLaunchIntent(layoutId, numViews);
        return (CustomTestActivity) sInstrumentation.startActivitySync(intent);
    }
}
+34 −0
Original line number Diff line number Diff line
@@ -19,6 +19,10 @@ package android.view.contentcapture;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteCallback;
import android.view.Choreographer;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

@@ -31,6 +35,8 @@ import com.android.perftests.contentcapture.R;
public class CustomTestActivity extends Activity {
    public static final String INTENT_EXTRA_LAYOUT_ID = "layout_id";
    public static final String INTENT_EXTRA_CUSTOM_VIEWS = "custom_view_number";
    static final String INTENT_EXTRA_FINISH_ON_IDLE = "finish";
    static final String INTENT_EXTRA_DRAW_CALLBACK = "draw_callback";
    public static final int MAX_VIEWS = 500;
    private static final int CUSTOM_CONTAINER_LAYOUT_ID = R.layout.test_container_activity;

@@ -47,6 +53,34 @@ public class CustomTestActivity extends Activity {
                        getIntent().getIntExtra(INTENT_EXTRA_CUSTOM_VIEWS, MAX_VIEWS));
            }
        }

        final RemoteCallback drawCallback = getIntent().getParcelableExtra(
                INTENT_EXTRA_DRAW_CALLBACK, RemoteCallback.class);
        if (drawCallback != null) {
            getWindow().getDecorView().addOnAttachStateChangeListener(
                    new View.OnAttachStateChangeListener() {
                        @Override
                        public void onViewAttachedToWindow(View v) {
                            Choreographer.getInstance().postCallback(
                                    Choreographer.CALLBACK_COMMIT,
                                    // Report that the first frame is drawn.
                                    () -> drawCallback.sendResult(null), null /* token */);
                        }

                        @Override
                        public void onViewDetachedFromWindow(View v) {
                        }
                    });
        }

        if (getIntent().getBooleanExtra(INTENT_EXTRA_FINISH_ON_IDLE, false)) {
            Looper.myQueue().addIdleHandler(() -> {
                // Finish without animation.
                finish();
                overridePendingTransition(0 /* enterAnim */, 0 /* exitAnim */);
                return false;
            });
        }
    }

    private void createCustomViews(LinearLayout root, int number) {
+22 −6
Original line number Diff line number Diff line
@@ -15,9 +15,10 @@
 */
package android.view.contentcapture;

import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.CREATED;
import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;

import android.content.Intent;
import android.os.RemoteCallback;
import android.perftests.utils.BenchmarkState;
import android.view.View;

@@ -80,17 +81,32 @@ public class LoginTest extends AbstractContentCapturePerfTestCase {
    }

    private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
        final Object drawNotifier = new Object();
        final Intent intent = getLaunchIntent(layoutId, numViews);
        intent.putExtra(CustomTestActivity.INTENT_EXTRA_FINISH_ON_IDLE, true);
        intent.putExtra(CustomTestActivity.INTENT_EXTRA_DRAW_CALLBACK,
                new RemoteCallback(result -> {
                    synchronized (drawNotifier) {
                        drawNotifier.notifyAll();
                    }
                }));
        final ActivityWatcher watcher = startWatcher();

        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            launchActivity(layoutId, numViews);
            mEntryActivity.startActivity(intent);
            synchronized (drawNotifier) {
                try {
                    drawNotifier.wait(GENERIC_TIMEOUT_MS);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            // Ignore the time to finish the activity
            state.pauseTiming();
            watcher.waitFor(CREATED);
            finishActivity();
            watcher.waitFor(DESTROYED);
            sInstrumentation.waitForIdleSync();
            state.resumeTiming();
        }
    }
@@ -142,12 +158,12 @@ public class LoginTest extends AbstractContentCapturePerfTestCase {
        while (state.keepRunning()) {
            // Only count the time of onVisibilityAggregated()
            state.pauseTiming();
            mActivityRule.runOnUiThread(() -> {
            sInstrumentation.runOnMainSync(() -> {
                state.resumeTiming();
                view.onVisibilityAggregated(false);
                state.pauseTiming();
            });
            mActivityRule.runOnUiThread(() -> {
            sInstrumentation.runOnMainSync(() -> {
                state.resumeTiming();
                view.onVisibilityAggregated(true);
                state.pauseTiming();