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

Commit 5bd439b7 authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Refine FilesAppPerfTest to improve consistency"

parents 5d384e0e 619a2252
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.documentsui.appperftests">

    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

    <application>
+81 −57
Original line number Diff line number Diff line
@@ -16,31 +16,35 @@

package com.android.documentsui;

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

import static org.junit.Assume.assumeNotNull;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.support.test.uiautomator.UiDevice;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import android.util.Log;

import org.junit.BeforeClass;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;

@RunWith(AndroidJUnit4.class)
public class FilesAppPerfTest {
    private static final String TAG = "FilesAppPerfTest";

    // Keys used to report metrics to APCT.
    private static final String KEY_FILES_COLD_START_PERFORMANCE_MEDIAN =
@@ -48,16 +52,31 @@ public class FilesAppPerfTest {
    private static final String KEY_FILES_WARM_START_PERFORMANCE_MEDIAN =
            "files-warm-start-performance-median";

    private static final String TARGET_PACKAGE = "com.android.documentsui";

    private static final int NUM_MEASUREMENTS = 10;
    private static final long REMOVAL_TIMEOUT_MS = 3000;
    private static final long TIMEOUT_INTERVAL_MS = 200;

    private Instrumentation mInstrumentation;
    private Context mContext;
    private LauncherActivity mLauncherActivity;
    private ActivityInfo mDocumentsUiActivityInfo;

    @Before
    public void setUp() {
        mInstrumentation = getInstrumentation();
        mContext = mInstrumentation.getContext();
        final ResolveInfo info = mContext.getPackageManager().resolveActivity(
                LauncherActivity.OPEN_DOCUMENT_INTENT, PackageManager.ResolveInfoFlags.of(0));
        assumeNotNull(info);
        mDocumentsUiActivityInfo = info.activityInfo;
        mLauncherActivity = (LauncherActivity) mInstrumentation.startActivitySync(
                new Intent(mContext, LauncherActivity.class).addFlags(
                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION));
    }

    private LauncherActivity mActivity;
    private static UiDevice mDevice;

    @BeforeClass
    public static void setUp() {
        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    @After
    public void tearDown() {
        mLauncherActivity.finishAndRemoveTask();
    }

    @Test
@@ -71,22 +90,31 @@ public class FilesAppPerfTest {
    }

    public void runFilesStartPerformanceTest(boolean cold) throws Exception {
        final String documentsUiPackageName = mDocumentsUiActivityInfo.packageName;
        String[] providerPackageNames = null;
        if (cold) {
            providerPackageNames = getDocumentsProviderPackageNames();
        }
        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
        long[] measurements = new long[NUM_MEASUREMENTS];
        for (int i = 0; i < NUM_MEASUREMENTS; i++) {
            if (cold) {
                // Kill all providers, as well as DocumentsUI to measure a cold start.
                killProviders();
                mDevice.executeShellCommand("am force-stop " + TARGET_PACKAGE);
                for (String pkgName : providerPackageNames) {
                    // Use kill-bg to avoid affecting other important services.
                    Log.i(TAG, "killBackgroundProcesses " + pkgName);
                    am.killBackgroundProcesses(pkgName);
                }
                Log.i(TAG, "forceStopPackage " + documentsUiPackageName);
                am.forceStopPackage(documentsUiPackageName);
                // Wait for any closing animations to finish.
                mInstrumentation.getUiAutomation().syncInputTransactions();
            }
            mDevice.waitForIdle();

            LauncherActivity.testCaseLatch = new CountDownLatch(1);
            mActivity = launchActivity(
                    InstrumentationRegistry.getInstrumentation().getTargetContext()
                            .getPackageName(),
                    LauncherActivity.class, null);
            LauncherActivity.testCaseLatch.await();
            measurements[i] = LauncherActivity.measurement;
            measurements[i] = mLauncherActivity.startAndWaitDocumentsUi();
            // The DocumentUi will finish automatically according to the request code for testing,
            // so wait until it is completely removed to avoid affecting next iteration.
            waitUntilDocumentsUiActivityRemoved();
        }

        reportMetrics(cold ? KEY_FILES_COLD_START_PERFORMANCE_MEDIAN
@@ -99,41 +127,37 @@ public class FilesAppPerfTest {
        final long median = measurements[NUM_MEASUREMENTS / 2 - 1];
        status.putDouble(key + "(ms)", median);

        InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
        mInstrumentation.sendStatus(Activity.RESULT_OK, status);
    }

    private void killProviders() throws Exception {
        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
        final PackageManager pm = context.getPackageManager();
        final ActivityManager am = (ActivityManager) context.getSystemService(
                Context.ACTIVITY_SERVICE);
    private String[] getDocumentsProviderPackageNames() {
        final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
        final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
        for (ResolveInfo info : providers) {
            final String packageName = info.providerInfo.packageName;
            am.killBackgroundProcesses(packageName);
        final List<ResolveInfo> providers = mContext.getPackageManager()
                .queryIntentContentProviders(intent, PackageManager.ResolveInfoFlags.of(0));
        final String[] pkgNames = new String[providers.size()];
        for (int i = 0; i < providers.size(); i++) {
            pkgNames[i] = providers.get(i).providerInfo.packageName;
        }
        return pkgNames;
    }

    private final <T extends Activity> T launchActivity(
            String pkg,
            Class<T> activityCls,
            Bundle extras) {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        if (extras != null) {
            intent.putExtras(extras);
    private void waitUntilDocumentsUiActivityRemoved() {
        final UiDevice uiDevice = UiDevice.getInstance(mInstrumentation);
        final String classPattern = new ComponentName(mDocumentsUiActivityInfo.packageName,
                mDocumentsUiActivityInfo.name).flattenToShortString();
        final long startTime = SystemClock.uptimeMillis();
        while (SystemClock.uptimeMillis() - startTime <= REMOVAL_TIMEOUT_MS) {
            SystemClock.sleep(TIMEOUT_INTERVAL_MS);
            final String windowTokenDump;
            try {
                windowTokenDump = uiDevice.executeShellCommand("dumpsys window tokens");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        return launchActivityWithIntent(pkg, activityCls, intent);
            if (!windowTokenDump.contains(classPattern)) {
                return;
            }

    private final <T extends Activity> T launchActivityWithIntent(
            String pkg,
            Class<T> activityCls,
            Intent intent) {
        intent.setClassName(pkg, activityCls.getName());
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        T activity = (T) InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
        return activity;
        }
        Log.i(TAG, "Removal timeout of " + classPattern);
    }
}
+19 −24
Original line number Diff line number Diff line
@@ -20,43 +20,38 @@ import static com.android.documentsui.base.Shared.EXTRA_BENCHMARK;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class LauncherActivity extends Activity {
    private static final String TARGET_PACKAGE = "com.android.documentsui";
    private static final int BENCHMARK_REQUEST_CODE = 1986;

    public static CountDownLatch testCaseLatch = null;
    public static long measurement = -1;
    static final Intent OPEN_DOCUMENT_INTENT = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    static {
        OPEN_DOCUMENT_INTENT.addCategory(Intent.CATEGORY_OPENABLE);
        OPEN_DOCUMENT_INTENT.putExtra(EXTRA_BENCHMARK, true);
        OPEN_DOCUMENT_INTENT.setType("*/*");
    }

    private long mStartTime = -1;
    private CountDownLatch mTestCaseLatch;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new Handler().post(new Runnable() {
            @Override public void run() {
                final Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT");
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.putExtra(EXTRA_BENCHMARK, true);
                intent.setType("*/*");

                mStartTime = System.currentTimeMillis();
                startActivityForResult(intent, BENCHMARK_REQUEST_CODE);
    /** Starts DocumentsUi and returns the duration until the result is received. */
    long startAndWaitDocumentsUi() throws InterruptedException {
        mTestCaseLatch = new CountDownLatch(1);
        final long startTime = SystemClock.elapsedRealtime();
        startActivityForResult(OPEN_DOCUMENT_INTENT, BENCHMARK_REQUEST_CODE);
        if (!mTestCaseLatch.await(10, TimeUnit.SECONDS)) {
            throw new RuntimeException("DocumentsUi is not responding");
        }
        });
        return SystemClock.elapsedRealtime() - startTime;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == BENCHMARK_REQUEST_CODE) {
            measurement = System.currentTimeMillis() - mStartTime;
            testCaseLatch.countDown();
            finish();
            mTestCaseLatch.countDown();
        }
    }
}