summaryrefslogtreecommitdiff
path: root/app-perf-tests
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2022-12-19 21:19:04 +0800
committer Riddle Hsu <riddlehsu@google.com> 2023-01-31 11:54:39 +0000
commit619a2252607a5592dd3e1dbd4993e3a1cb4de7b3 (patch)
treecf91778dc65632e4af72ec15f462bd2419e81fb5 /app-perf-tests
parent3b9ef97c7989e8e424aae896b49b57118fd95456 (diff)
Refine FilesAppPerfTest to improve consistency
1. Query package name by intent rather than hardcoded. Otherwise the force-stop may not kill the target app. It is expected that metric files-cold-start-performance-median will increase, because it was warm-start (only provider is killed). 2. Change from looping "-> launcher activity -> target activity" to only "-> target activity", to eliminate uninterested factors from transition between home. 3. Wait until the removal of previous target activity is completed to start next iteration. So the metrics could be stabler by focusing on measuring the launch flow. 4. Remove waitForIdle to avoid non deterministic waiting according to accessibility event. It usually means UI interaction is idle but not the app is idle. This can also reduce test execution time by more than 70%, e.g. warm-start 40s to 9s. Bug: 258902050 Bug: 266684779 Test: atest FilesAppPerfTest Change-Id: I8da0050105f02e3ba405b4b3184f56450befd358
Diffstat (limited to 'app-perf-tests')
-rw-r--r--app-perf-tests/AndroidManifest.xml2
-rw-r--r--app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java138
-rw-r--r--app-perf-tests/src/com/android/documentsui/LauncherActivity.java43
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();
}
}
}