diff options
3 files changed, 102 insertions, 81 deletions
diff --git a/app-perf-tests/AndroidManifest.xml b/app-perf-tests/AndroidManifest.xml index 0ed5e4540..8adf7da2d 100644 --- a/app-perf-tests/AndroidManifest.xml +++ b/app-perf-tests/AndroidManifest.xml @@ -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> diff --git a/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java index 670391e62..8366c89f5 100644 --- a/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java +++ b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java @@ -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); + } + if (!windowTokenDump.contains(classPattern)) { + return; + } } - return launchActivityWithIntent(pkg, activityCls, intent); - } - - 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); } } diff --git a/app-perf-tests/src/com/android/documentsui/LauncherActivity.java b/app-perf-tests/src/com/android/documentsui/LauncherActivity.java index dd692c694..e67ed9136 100644 --- a/app-perf-tests/src/com/android/documentsui/LauncherActivity.java +++ b/app-perf-tests/src/com/android/documentsui/LauncherActivity.java @@ -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(); } } } |