diff options
-rw-r--r-- | app-perf-tests/Android.mk | 18 | ||||
-rw-r--r-- | app-perf-tests/AndroidManifest.xml | 18 | ||||
-rw-r--r-- | app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java | 102 | ||||
-rw-r--r-- | app-perf-tests/src/com/android/documentsui/LauncherActivity.java | 64 | ||||
-rw-r--r-- | src/com/android/documentsui/BaseActivity.java | 44 | ||||
-rw-r--r-- | src/com/android/documentsui/Shared.java | 5 |
6 files changed, 250 insertions, 1 deletions
diff --git a/app-perf-tests/Android.mk b/app-perf-tests/Android.mk new file mode 100644 index 000000000..3f12906b7 --- /dev/null +++ b/app-perf-tests/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +#LOCAL_SDK_VERSION := current + +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + +LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner +LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator + +LOCAL_PACKAGE_NAME := DocumentsUIAppPerfTests +LOCAL_INSTRUMENTATION_FOR := DocumentsUI + +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + diff --git a/app-perf-tests/AndroidManifest.xml b/app-perf-tests/AndroidManifest.xml new file mode 100644 index 000000000..1c3ed80ad --- /dev/null +++ b/app-perf-tests/AndroidManifest.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.documentsui.appperftests"> + + <application> + <uses-library android:name="android.test.runner" /> + + <activity + android:name="com.android.documentsui.LauncherActivity" /> + </application> + + <!-- This package instrumentates itself, so the DocumentsUI process can be killed without + killing the testing package. --> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.documentsui.appperftests" + android:label="App performance tests for DocumentsUI" /> + +</manifest> diff --git a/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java new file mode 100644 index 000000000..d6e8a96f3 --- /dev/null +++ b/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.provider.DocumentsContract; +import android.support.test.uiautomator.UiDevice; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +@LargeTest +public class FilesAppPerfTest extends InstrumentationTestCase { + + // Keys used to report metrics to APCT. + private static final String KEY_FILES_COLD_START_PERFORMANCE_MEDIAN = + "files-cold-start-performance-median"; + 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 LauncherActivity mActivity; + private UiDevice mDevice; + + @Override + public void setUp() { + mDevice = UiDevice.getInstance(getInstrumentation()); + } + + public void testFilesColdStartPerformance() throws Exception { + runFilesStartPerformanceTest(true); + } + + public void testFilesWarmStartPerformance() throws Exception { + runFilesStartPerformanceTest(false); + } + + public void runFilesStartPerformanceTest(boolean cold) throws Exception { + 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); + } + mDevice.waitForIdle(); + + LauncherActivity.testCaseLatch = new CountDownLatch(1); + mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), + LauncherActivity.class, null); + LauncherActivity.testCaseLatch.await(); + measurements[i] = LauncherActivity.measurement; + } + + reportMetrics(cold ? KEY_FILES_COLD_START_PERFORMANCE_MEDIAN + : KEY_FILES_WARM_START_PERFORMANCE_MEDIAN, measurements); + } + + private void reportMetrics(String key, long[] measurements) { + final Bundle status = new Bundle(); + Arrays.sort(measurements); + final long median = measurements[NUM_MEASUREMENTS / 2 - 1]; + status.putDouble(key, median); + + getInstrumentation().sendStatus(Activity.RESULT_OK, status); + } + + private void killProviders() throws Exception { + final PackageManager pm = getInstrumentation().getContext().getPackageManager(); + 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; + mDevice.executeShellCommand("am force-stop " + packageName); + } + } +} diff --git a/app-perf-tests/src/com/android/documentsui/LauncherActivity.java b/app-perf-tests/src/com/android/documentsui/LauncherActivity.java new file mode 100644 index 000000000..21fc52e00 --- /dev/null +++ b/app-perf-tests/src/com/android/documentsui/LauncherActivity.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui; + +import static com.android.documentsui.Shared.EXTRA_BENCHMARK; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; + +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; + + private long mStartTime = -1; + + @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); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == BENCHMARK_REQUEST_CODE) { + measurement = System.currentTimeMillis() - mStartTime; + testCaseLatch.countDown(); + finish(); + } + } +} diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java index 1a8ce18ce..b5f8d64de 100644 --- a/src/com/android/documentsui/BaseActivity.java +++ b/src/com/android/documentsui/BaseActivity.java @@ -17,6 +17,7 @@ package com.android.documentsui; import static com.android.documentsui.Shared.DEBUG; +import static com.android.documentsui.Shared.EXTRA_BENCHMARK; import static com.android.documentsui.State.MODE_GRID; import android.app.Activity; @@ -30,6 +31,9 @@ import android.content.pm.ProviderInfo; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.Handler; +import android.os.MessageQueue; +import android.os.MessageQueue.IdleHandler; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; import android.support.annotation.CallSuper; @@ -60,6 +64,8 @@ import java.util.concurrent.Executor; public abstract class BaseActivity extends Activity implements SearchManagerListener, NavigationView.Environment { + private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests"; + State mState; RootsCache mRoots; SearchViewManager mSearchManager; @@ -92,11 +98,20 @@ public abstract class BaseActivity extends Activity public void onCreate(Bundle icicle) { super.onCreate(icicle); + final Intent intent = getIntent(); + + // If startup benchmark is requested by a whitelisted testing package, then close the + // activity once idle, and notify the testing activity. + if (intent.getBooleanExtra(EXTRA_BENCHMARK, false) && + BENCHMARK_TESTING_PACKAGE.equals(getCallingPackage())) { + closeOnIdleForTesting(); + } + setContentView(mLayoutId); mDrawer = DrawerController.create(this); mState = getState(icicle); - Metrics.logActivityLaunch(this, mState, getIntent()); + Metrics.logActivityLaunch(this, mState, intent); mRoots = DocumentsApplication.getRootsCache(this); @@ -668,6 +683,33 @@ public abstract class BaseActivity extends Activity } } + /** + * Closes the activity when it's idle. Used only for tests. + */ + private void closeOnIdleForTesting() { + addEventListener(new EventListener() { + @Override + public void onDirectoryNavigated(Uri uri) { + } + + @Override + public void onDirectoryLoaded(Uri uri) { + getMainLooper().getQueue().addIdleHandler(new IdleHandler() { + @Override + public boolean queueIdle() { + setResult(RESULT_OK); + finish(); + return false; + } + }); + new Handler().post(new Runnable() { + @Override public void run() { + } + }); + } + }); + } + private static final class HandleRootsChangedTask extends PairedTask<BaseActivity, RootInfo, RootInfo> { DocumentInfo mHome; diff --git a/src/com/android/documentsui/Shared.java b/src/com/android/documentsui/Shared.java index b53942106..1fbf0440e 100644 --- a/src/com/android/documentsui/Shared.java +++ b/src/com/android/documentsui/Shared.java @@ -86,6 +86,11 @@ public final class Shared { */ public static final String EXTRA_IGNORE_STATE = "ignoreState"; + /** + * Extra for an Intent for enabling performance benchmark. Used only by tests. + */ + public static final String EXTRA_BENCHMARK = "com.android.documentsui.benchmark"; + private static final Collator sCollator; static { |