Loading app-perf-tests/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -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> Loading app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java +81 −57 Original line number Diff line number Diff line Loading @@ -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 = Loading @@ -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 Loading @@ -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 Loading @@ -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); } } app-perf-tests/src/com/android/documentsui/LauncherActivity.java +19 −24 Original line number Diff line number Diff line Loading @@ -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(); } } } Loading
app-perf-tests/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -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> Loading
app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java +81 −57 Original line number Diff line number Diff line Loading @@ -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 = Loading @@ -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 Loading @@ -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 Loading @@ -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); } }
app-perf-tests/src/com/android/documentsui/LauncherActivity.java +19 −24 Original line number Diff line number Diff line Loading @@ -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(); } } }