diff options
Diffstat (limited to 'apct-tests')
50 files changed, 3880 insertions, 212 deletions
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml index 9c8abc32eb72..1e3532b3c1ef 100644 --- a/apct-tests/perftests/autofill/AndroidManifest.xml +++ b/apct-tests/perftests/autofill/AndroidManifest.xml @@ -18,7 +18,7 @@ <application> <uses-library android:name="android.test.runner" /> - <activity android:name="android.perftests.utils.StubActivity"> + <activity android:name="android.perftests.utils.PerfTestActivity"> <intent-filter> <action android:name="com.android.perftests.core.PERFTEST" /> </intent-filter> diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java index 6979f0f0875d..48ce8ab2fce5 100644 --- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java +++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java @@ -20,9 +20,9 @@ import static org.junit.Assert.assertTrue; import android.os.Looper; import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.PerfTestActivity; import android.perftests.utils.SettingsHelper; import android.perftests.utils.SettingsStateKeeperRule; -import android.perftests.utils.StubActivity; import android.provider.Settings; import androidx.test.InstrumentationRegistry; @@ -46,8 +46,8 @@ public abstract class AbstractAutofillPerfTestCase { Settings.Secure.AUTOFILL_SERVICE); @Rule - public ActivityTestRule<StubActivity> mActivityRule = - new ActivityTestRule<StubActivity>(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); @@ -68,7 +68,7 @@ public abstract class AbstractAutofillPerfTestCase { Looper.getMainLooper().getThread() == Thread.currentThread()); assertTrue("We should be running on the main thread", Looper.myLooper() == Looper.getMainLooper()); - StubActivity activity = mActivityRule.getActivity(); + PerfTestActivity activity = mActivityRule.getActivity(); activity.setContentView(mLayoutId); onCreate(activity); }); @@ -89,9 +89,9 @@ public abstract class AbstractAutofillPerfTestCase { } /** - * Initializes the {@link StubActivity} after it was launched. + * Initializes the {@link PerfTestActivity} after it was launched. */ - protected abstract void onCreate(StubActivity activity); + protected abstract void onCreate(PerfTestActivity activity); /** * Uses the {@code settings} binary to set the autofill service. diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java index 80908266c5c0..fb5ea80e6ed1 100644 --- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java +++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java @@ -20,7 +20,7 @@ import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN; import android.perftests.utils.BenchmarkState; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.view.View; import android.widget.EditText; @@ -39,7 +39,7 @@ public class LoginTest extends AbstractAutofillPerfTestCase { } @Override - protected void onCreate(StubActivity activity) { + protected void onCreate(PerfTestActivity activity) { View root = activity.getWindow().getDecorView(); mUsername = root.findViewById(R.id.username); mPassword = root.findViewById(R.id.password); diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index 3f87a1c8b598..968478c3f338 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -9,8 +9,11 @@ LOCAL_SRC_FILES := \ src/android/os/ISomeService.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ + androidx.appcompat_appcompat \ androidx.test.rules \ androidx.annotation_annotation \ + apct-perftests-overlay-apps \ + apct-perftests-resources-manager-apps \ apct-perftests-utils \ guava @@ -25,5 +28,6 @@ LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script LOCAL_COMPATIBILITY_SUITE += device-tests +LOCAL_CERTIFICATE := platform -include $(BUILD_PACKAGE) +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml index a564a4d27fb3..290f178fb669 100644 --- a/apct-tests/perftests/core/AndroidManifest.xml +++ b/apct-tests/perftests/core/AndroidManifest.xml @@ -5,12 +5,15 @@ <permission android:name="com.android.perftests.core.TestPermission" /> <uses-permission android:name="com.android.perftests.core.TestPermission" /> - <uses-permission - android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" /> + <uses-permission android:name="android.permission.DELETE_PACKAGES" /> + <uses-permission android:name="android.permission.GET_ACCOUNTS" /> + <uses-permission android:name="android.permission.INSTALL_PACKAGES"/> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <application> <uses-library android:name="android.test.runner" /> - <activity android:name="android.perftests.utils.StubActivity"> + <activity android:name="android.perftests.utils.PerfTestActivity"> <intent-filter> <action android:name="com.android.perftests.core.PERFTEST" /> </intent-filter> diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml index 1b289130124f..478cfc1fe811 100644 --- a/apct-tests/perftests/core/AndroidTest.xml +++ b/apct-tests/perftests/core/AndroidTest.xml @@ -25,4 +25,9 @@ <option name="package" value="com.android.perftests.core" /> <option name="hidden-api-checks" value="false"/> </test> + + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="directory-keys" value="/data/local/CorePerfTests" /> + <option name="collect-on-run-ended-only" value="true" /> + </metrics_collector> </configuration> diff --git a/apct-tests/perftests/core/apps/overlay/Android.bp b/apct-tests/perftests/core/apps/overlay/Android.bp new file mode 100644 index 000000000000..7bee30ee9cb4 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/Android.bp @@ -0,0 +1,188 @@ +// Copyright (C) 2019 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. + +android_test_helper_app { + name: "Overlay0", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay0", + ] +} + +android_test_helper_app { + name: "Overlay1", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay1", + ] +} + +android_test_helper_app { + name: "Overlay2", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay2", + ] +} + +android_test_helper_app { + name: "Overlay3", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay3", + ] +} + +android_test_helper_app { + name: "Overlay4", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay4", + ] +} + +android_test_helper_app { + name: "Overlay5", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay5", + ] +} + +android_test_helper_app { + name: "Overlay6", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay6", + ] +} + +android_test_helper_app { + name: "Overlay7", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay7", + ] +} +android_test_helper_app { + name: "Overlay8", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay8", + ] +} + +android_test_helper_app { + name: "Overlay9", + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay9", + ] +} + +android_test_helper_app { + name: "LargeOverlay0", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large0", + ] +} + +android_test_helper_app { + name: "LargeOverlay1", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large1", + ] +} + +android_test_helper_app { + name: "LargeOverlay2", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large2", + ] +} + +android_test_helper_app { + name: "LargeOverlay3", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large3", + ] +} + +android_test_helper_app { + name: "LargeOverlay4", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large4", + ] +} + +android_test_helper_app { + name: "LargeOverlay5", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large5", + ] +} + +android_test_helper_app { + name: "LargeOverlay6", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large6", + ] +} + +android_test_helper_app { + name: "LargeOverlay7", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large7", + ] +} + +android_test_helper_app { + name: "LargeOverlay8", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large8", + ] +} + +android_test_helper_app { + name: "LargeOverlay9", + resource_dirs : [ "res_large" ], + aaptflags: [ + "--rename-manifest-package com.android.perftests.overlay.large9", + ] +} + +java_library { + name: "apct-perftests-overlay-apps", + java_resources: [ + ":Overlay0", + ":Overlay1", + ":Overlay2", + ":Overlay3", + ":Overlay4", + ":Overlay5", + ":Overlay6", + ":Overlay7", + ":Overlay8", + ":Overlay9", + ":LargeOverlay0", + ":LargeOverlay1", + ":LargeOverlay2", + ":LargeOverlay3", + ":LargeOverlay4", + ":LargeOverlay5", + ":LargeOverlay6", + ":LargeOverlay7", + ":LargeOverlay8", + ":LargeOverlay9", + ], +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml b/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml new file mode 100644 index 000000000000..52f5a89bc9e4 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.perftests.overlay"> + <application android:hasCode="false" /> + <uses-sdk android:targetSdkVersion="29" /> + <overlay android:targetPackage="com.android.perftests.core" android:targetName="TestResources"/> +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/overlay/res/values/values.xml b/apct-tests/perftests/core/apps/overlay/res/values/values.xml new file mode 100644 index 000000000000..a1a8d83eb193 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/res/values/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> + +<resources> + <string name="short_text">B</string> +</resources> diff --git a/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml b/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml new file mode 100644 index 000000000000..e74144648e32 --- /dev/null +++ b/apct-tests/perftests/core/apps/overlay/res_large/values/values.xml @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> + +<resources> + <string name="short_text000">B</string> + <string name="short_text001">B</string> + <string name="short_text002">B</string> + <string name="short_text003">B</string> + <string name="short_text004">B</string> + <string name="short_text005">B</string> + <string name="short_text006">B</string> + <string name="short_text007">B</string> + <string name="short_text008">B</string> + <string name="short_text009">B</string> + <string name="short_text010">B</string> + <string name="short_text011">B</string> + <string name="short_text012">B</string> + <string name="short_text013">B</string> + <string name="short_text014">B</string> + <string name="short_text015">B</string> + <string name="short_text016">B</string> + <string name="short_text017">B</string> + <string name="short_text018">B</string> + <string name="short_text019">B</string> + <string name="short_text020">B</string> + <string name="short_text021">B</string> + <string name="short_text022">B</string> + <string name="short_text023">B</string> + <string name="short_text024">B</string> + <string name="short_text025">B</string> + <string name="short_text026">B</string> + <string name="short_text027">B</string> + <string name="short_text028">B</string> + <string name="short_text029">B</string> + <string name="short_text030">B</string> + <string name="short_text031">B</string> + <string name="short_text032">B</string> + <string name="short_text033">B</string> + <string name="short_text034">B</string> + <string name="short_text035">B</string> + <string name="short_text036">B</string> + <string name="short_text037">B</string> + <string name="short_text038">B</string> + <string name="short_text039">B</string> + <string name="short_text040">B</string> + <string name="short_text041">B</string> + <string name="short_text042">B</string> + <string name="short_text043">B</string> + <string name="short_text044">B</string> + <string name="short_text045">B</string> + <string name="short_text046">B</string> + <string name="short_text047">B</string> + <string name="short_text048">B</string> + <string name="short_text049">B</string> + <string name="short_text050">B</string> + <string name="short_text051">B</string> + <string name="short_text052">B</string> + <string name="short_text053">B</string> + <string name="short_text054">B</string> + <string name="short_text055">B</string> + <string name="short_text056">B</string> + <string name="short_text057">B</string> + <string name="short_text058">B</string> + <string name="short_text059">B</string> + <string name="short_text060">B</string> + <string name="short_text061">B</string> + <string name="short_text062">B</string> + <string name="short_text063">B</string> + <string name="short_text064">B</string> + <string name="short_text065">B</string> + <string name="short_text066">B</string> + <string name="short_text067">B</string> + <string name="short_text068">B</string> + <string name="short_text069">B</string> + <string name="short_text070">B</string> + <string name="short_text071">B</string> + <string name="short_text072">B</string> + <string name="short_text073">B</string> + <string name="short_text074">B</string> + <string name="short_text075">B</string> + <string name="short_text076">B</string> + <string name="short_text077">B</string> + <string name="short_text078">B</string> + <string name="short_text079">B</string> + <string name="short_text080">B</string> + <string name="short_text081">B</string> + <string name="short_text082">B</string> + <string name="short_text083">B</string> + <string name="short_text084">B</string> + <string name="short_text085">B</string> + <string name="short_text086">B</string> + <string name="short_text087">B</string> + <string name="short_text088">B</string> + <string name="short_text089">B</string> + <string name="short_text090">B</string> + <string name="short_text091">B</string> + <string name="short_text092">B</string> + <string name="short_text093">B</string> + <string name="short_text094">B</string> + <string name="short_text095">B</string> + <string name="short_text096">B</string> + <string name="short_text097">B</string> + <string name="short_text098">B</string> + <string name="short_text099">B</string> + <string name="short_text100">B</string> + <string name="short_text101">B</string> + <string name="short_text102">B</string> + <string name="short_text103">B</string> + <string name="short_text104">B</string> + <string name="short_text105">B</string> + <string name="short_text106">B</string> + <string name="short_text107">B</string> + <string name="short_text108">B</string> + <string name="short_text109">B</string> + <string name="short_text110">B</string> + <string name="short_text111">B</string> + <string name="short_text112">B</string> + <string name="short_text113">B</string> + <string name="short_text114">B</string> + <string name="short_text115">B</string> + <string name="short_text116">B</string> + <string name="short_text117">B</string> + <string name="short_text118">B</string> + <string name="short_text119">B</string> + <string name="short_text120">B</string> + <string name="short_text121">B</string> + <string name="short_text122">B</string> + <string name="short_text123">B</string> + <string name="short_text124">B</string> + <string name="short_text125">B</string> + <string name="short_text126">B</string> + <string name="short_text127">B</string> + <string name="short_text128">B</string> + <string name="short_text129">B</string> + <string name="short_text130">B</string> + <string name="short_text131">B</string> + <string name="short_text132">B</string> + <string name="short_text133">B</string> + <string name="short_text134">B</string> + <string name="short_text135">B</string> + <string name="short_text136">B</string> + <string name="short_text137">B</string> + <string name="short_text138">B</string> + <string name="short_text139">B</string> + <string name="short_text140">B</string> + <string name="short_text141">B</string> + <string name="short_text142">B</string> + <string name="short_text143">B</string> + <string name="short_text144">B</string> + <string name="short_text145">B</string> + <string name="short_text146">B</string> + <string name="short_text147">B</string> + <string name="short_text148">B</string> + <string name="short_text149">B</string> + <string name="short_text150">B</string> + <string name="short_text151">B</string> + <string name="short_text152">B</string> + <string name="short_text153">B</string> + <string name="short_text154">B</string> + <string name="short_text155">B</string> + <string name="short_text156">B</string> + <string name="short_text157">B</string> + <string name="short_text158">B</string> + <string name="short_text159">B</string> + <string name="short_text160">B</string> + <string name="short_text161">B</string> + <string name="short_text162">B</string> + <string name="short_text163">B</string> + <string name="short_text164">B</string> + <string name="short_text165">B</string> + <string name="short_text166">B</string> + <string name="short_text167">B</string> + <string name="short_text168">B</string> + <string name="short_text169">B</string> + <string name="short_text170">B</string> + <string name="short_text171">B</string> + <string name="short_text172">B</string> + <string name="short_text173">B</string> + <string name="short_text174">B</string> + <string name="short_text175">B</string> + <string name="short_text176">B</string> + <string name="short_text177">B</string> + <string name="short_text178">B</string> + <string name="short_text179">B</string> + <string name="short_text180">B</string> + <string name="short_text181">B</string> + <string name="short_text182">B</string> + <string name="short_text183">B</string> + <string name="short_text184">B</string> + <string name="short_text185">B</string> + <string name="short_text186">B</string> + <string name="short_text187">B</string> + <string name="short_text188">B</string> + <string name="short_text189">B</string> + <string name="short_text190">B</string> + <string name="short_text191">B</string> + <string name="short_text192">B</string> + <string name="short_text193">B</string> + <string name="short_text194">B</string> + <string name="short_text195">B</string> + <string name="short_text196">B</string> + <string name="short_text197">B</string> + <string name="short_text198">B</string> + <string name="short_text199">B</string> + <string name="short_text200">B</string> + <string name="short_text201">B</string> + <string name="short_text202">B</string> + <string name="short_text203">B</string> + <string name="short_text204">B</string> + <string name="short_text205">B</string> + <string name="short_text206">B</string> + <string name="short_text207">B</string> + <string name="short_text208">B</string> + <string name="short_text209">B</string> + <string name="short_text210">B</string> + <string name="short_text211">B</string> + <string name="short_text212">B</string> + <string name="short_text213">B</string> + <string name="short_text214">B</string> + <string name="short_text215">B</string> + <string name="short_text216">B</string> + <string name="short_text217">B</string> + <string name="short_text218">B</string> + <string name="short_text219">B</string> + <string name="short_text220">B</string> + <string name="short_text221">B</string> + <string name="short_text222">B</string> + <string name="short_text223">B</string> + <string name="short_text224">B</string> + <string name="short_text225">B</string> + <string name="short_text226">B</string> + <string name="short_text227">B</string> + <string name="short_text228">B</string> + <string name="short_text229">B</string> + <string name="short_text230">B</string> + <string name="short_text231">B</string> + <string name="short_text232">B</string> + <string name="short_text233">B</string> + <string name="short_text234">B</string> + <string name="short_text235">B</string> + <string name="short_text236">B</string> + <string name="short_text237">B</string> + <string name="short_text238">B</string> + <string name="short_text239">B</string> + <string name="short_text240">B</string> + <string name="short_text241">B</string> + <string name="short_text242">B</string> + <string name="short_text243">B</string> + <string name="short_text244">B</string> + <string name="short_text245">B</string> + <string name="short_text246">B</string> + <string name="short_text247">B</string> + <string name="short_text248">B</string> + <string name="short_text249">B</string> + <string name="short_text250">B</string> + <string name="short_text251">B</string> + <string name="short_text252">B</string> + <string name="short_text253">B</string> + <string name="short_text254">B</string> + <string name="short_text255">B</string> +</resources> diff --git a/apct-tests/perftests/core/apps/reources_manager/Android.bp b/apct-tests/perftests/core/apps/reources_manager/Android.bp new file mode 100644 index 000000000000..451613236140 --- /dev/null +++ b/apct-tests/perftests/core/apps/reources_manager/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2019 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. + +android_test_helper_app { + name: "LargeResourcesCompressed", + static_libs: [ "androidx.appcompat_appcompat" ], +} + +genrule { + name: "LargeResourcesUncompressed", + srcs: [ ":LargeResourcesCompressed" ], + out: ["LargeResourcesUncompressed.apk"], + cmd: "cp $(in) $(out) && unzip -o $(out) resources.arsc" + + " && zip $(out) resources.arsc" +} + +java_library { + name: "apct-perftests-resources-manager-apps", + java_resources: [ + ":LargeResourcesCompressed", + ":LargeResourcesUncompressed", + ], +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml b/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml new file mode 100644 index 000000000000..adb4e406c608 --- /dev/null +++ b/apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="fake.android"> + <application android:hasCode="false" /> + <uses-sdk android:targetSdkVersion="29" /> +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/core/res/color/color_state_list.xml b/apct-tests/perftests/core/res/color/color_state_list.xml new file mode 100644 index 000000000000..142e47ae2738 --- /dev/null +++ b/apct-tests/perftests/core/res/color/color_state_list.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_focused="true" + android:color="#000000" /> + <item android:state_pressed="true" + android:state_enabled="false" + android:color="#212121" /> + <item android:state_enabled="false" + android:color="#414141" /> + <item android:color="#616161" /> +</selector>
\ No newline at end of file diff --git a/apct-tests/perftests/core/res/values/overlayable.xml b/apct-tests/perftests/core/res/values/overlayable.xml new file mode 100644 index 000000000000..70cedd7b0b75 --- /dev/null +++ b/apct-tests/perftests/core/res/values/overlayable.xml @@ -0,0 +1,280 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 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 + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <overlayable name="TestResources"> + <policy type="public"> + <item type="string" name="short_text" /> + <item type="string" name="short_text000" /> + <item type="string" name="short_text001" /> + <item type="string" name="short_text002" /> + <item type="string" name="short_text003" /> + <item type="string" name="short_text004" /> + <item type="string" name="short_text005" /> + <item type="string" name="short_text006" /> + <item type="string" name="short_text007" /> + <item type="string" name="short_text008" /> + <item type="string" name="short_text009" /> + <item type="string" name="short_text010" /> + <item type="string" name="short_text011" /> + <item type="string" name="short_text012" /> + <item type="string" name="short_text013" /> + <item type="string" name="short_text014" /> + <item type="string" name="short_text015" /> + <item type="string" name="short_text016" /> + <item type="string" name="short_text017" /> + <item type="string" name="short_text018" /> + <item type="string" name="short_text019" /> + <item type="string" name="short_text020" /> + <item type="string" name="short_text021" /> + <item type="string" name="short_text022" /> + <item type="string" name="short_text023" /> + <item type="string" name="short_text024" /> + <item type="string" name="short_text025" /> + <item type="string" name="short_text026" /> + <item type="string" name="short_text027" /> + <item type="string" name="short_text028" /> + <item type="string" name="short_text029" /> + <item type="string" name="short_text030" /> + <item type="string" name="short_text031" /> + <item type="string" name="short_text032" /> + <item type="string" name="short_text033" /> + <item type="string" name="short_text034" /> + <item type="string" name="short_text035" /> + <item type="string" name="short_text036" /> + <item type="string" name="short_text037" /> + <item type="string" name="short_text038" /> + <item type="string" name="short_text039" /> + <item type="string" name="short_text040" /> + <item type="string" name="short_text041" /> + <item type="string" name="short_text042" /> + <item type="string" name="short_text043" /> + <item type="string" name="short_text044" /> + <item type="string" name="short_text045" /> + <item type="string" name="short_text046" /> + <item type="string" name="short_text047" /> + <item type="string" name="short_text048" /> + <item type="string" name="short_text049" /> + <item type="string" name="short_text050" /> + <item type="string" name="short_text051" /> + <item type="string" name="short_text052" /> + <item type="string" name="short_text053" /> + <item type="string" name="short_text054" /> + <item type="string" name="short_text055" /> + <item type="string" name="short_text056" /> + <item type="string" name="short_text057" /> + <item type="string" name="short_text058" /> + <item type="string" name="short_text059" /> + <item type="string" name="short_text060" /> + <item type="string" name="short_text061" /> + <item type="string" name="short_text062" /> + <item type="string" name="short_text063" /> + <item type="string" name="short_text064" /> + <item type="string" name="short_text065" /> + <item type="string" name="short_text066" /> + <item type="string" name="short_text067" /> + <item type="string" name="short_text068" /> + <item type="string" name="short_text069" /> + <item type="string" name="short_text070" /> + <item type="string" name="short_text071" /> + <item type="string" name="short_text072" /> + <item type="string" name="short_text073" /> + <item type="string" name="short_text074" /> + <item type="string" name="short_text075" /> + <item type="string" name="short_text076" /> + <item type="string" name="short_text077" /> + <item type="string" name="short_text078" /> + <item type="string" name="short_text079" /> + <item type="string" name="short_text080" /> + <item type="string" name="short_text081" /> + <item type="string" name="short_text082" /> + <item type="string" name="short_text083" /> + <item type="string" name="short_text084" /> + <item type="string" name="short_text085" /> + <item type="string" name="short_text086" /> + <item type="string" name="short_text087" /> + <item type="string" name="short_text088" /> + <item type="string" name="short_text089" /> + <item type="string" name="short_text090" /> + <item type="string" name="short_text091" /> + <item type="string" name="short_text092" /> + <item type="string" name="short_text093" /> + <item type="string" name="short_text094" /> + <item type="string" name="short_text095" /> + <item type="string" name="short_text096" /> + <item type="string" name="short_text097" /> + <item type="string" name="short_text098" /> + <item type="string" name="short_text099" /> + <item type="string" name="short_text100" /> + <item type="string" name="short_text101" /> + <item type="string" name="short_text102" /> + <item type="string" name="short_text103" /> + <item type="string" name="short_text104" /> + <item type="string" name="short_text105" /> + <item type="string" name="short_text106" /> + <item type="string" name="short_text107" /> + <item type="string" name="short_text108" /> + <item type="string" name="short_text109" /> + <item type="string" name="short_text110" /> + <item type="string" name="short_text111" /> + <item type="string" name="short_text112" /> + <item type="string" name="short_text113" /> + <item type="string" name="short_text114" /> + <item type="string" name="short_text115" /> + <item type="string" name="short_text116" /> + <item type="string" name="short_text117" /> + <item type="string" name="short_text118" /> + <item type="string" name="short_text119" /> + <item type="string" name="short_text120" /> + <item type="string" name="short_text121" /> + <item type="string" name="short_text122" /> + <item type="string" name="short_text123" /> + <item type="string" name="short_text124" /> + <item type="string" name="short_text125" /> + <item type="string" name="short_text126" /> + <item type="string" name="short_text127" /> + <item type="string" name="short_text128" /> + <item type="string" name="short_text129" /> + <item type="string" name="short_text130" /> + <item type="string" name="short_text131" /> + <item type="string" name="short_text132" /> + <item type="string" name="short_text133" /> + <item type="string" name="short_text134" /> + <item type="string" name="short_text135" /> + <item type="string" name="short_text136" /> + <item type="string" name="short_text137" /> + <item type="string" name="short_text138" /> + <item type="string" name="short_text139" /> + <item type="string" name="short_text140" /> + <item type="string" name="short_text141" /> + <item type="string" name="short_text142" /> + <item type="string" name="short_text143" /> + <item type="string" name="short_text144" /> + <item type="string" name="short_text145" /> + <item type="string" name="short_text146" /> + <item type="string" name="short_text147" /> + <item type="string" name="short_text148" /> + <item type="string" name="short_text149" /> + <item type="string" name="short_text150" /> + <item type="string" name="short_text151" /> + <item type="string" name="short_text152" /> + <item type="string" name="short_text153" /> + <item type="string" name="short_text154" /> + <item type="string" name="short_text155" /> + <item type="string" name="short_text156" /> + <item type="string" name="short_text157" /> + <item type="string" name="short_text158" /> + <item type="string" name="short_text159" /> + <item type="string" name="short_text160" /> + <item type="string" name="short_text161" /> + <item type="string" name="short_text162" /> + <item type="string" name="short_text163" /> + <item type="string" name="short_text164" /> + <item type="string" name="short_text165" /> + <item type="string" name="short_text166" /> + <item type="string" name="short_text167" /> + <item type="string" name="short_text168" /> + <item type="string" name="short_text169" /> + <item type="string" name="short_text170" /> + <item type="string" name="short_text171" /> + <item type="string" name="short_text172" /> + <item type="string" name="short_text173" /> + <item type="string" name="short_text174" /> + <item type="string" name="short_text175" /> + <item type="string" name="short_text176" /> + <item type="string" name="short_text177" /> + <item type="string" name="short_text178" /> + <item type="string" name="short_text179" /> + <item type="string" name="short_text180" /> + <item type="string" name="short_text181" /> + <item type="string" name="short_text182" /> + <item type="string" name="short_text183" /> + <item type="string" name="short_text184" /> + <item type="string" name="short_text185" /> + <item type="string" name="short_text186" /> + <item type="string" name="short_text187" /> + <item type="string" name="short_text188" /> + <item type="string" name="short_text189" /> + <item type="string" name="short_text190" /> + <item type="string" name="short_text191" /> + <item type="string" name="short_text192" /> + <item type="string" name="short_text193" /> + <item type="string" name="short_text194" /> + <item type="string" name="short_text195" /> + <item type="string" name="short_text196" /> + <item type="string" name="short_text197" /> + <item type="string" name="short_text198" /> + <item type="string" name="short_text199" /> + <item type="string" name="short_text200" /> + <item type="string" name="short_text201" /> + <item type="string" name="short_text202" /> + <item type="string" name="short_text203" /> + <item type="string" name="short_text204" /> + <item type="string" name="short_text205" /> + <item type="string" name="short_text206" /> + <item type="string" name="short_text207" /> + <item type="string" name="short_text208" /> + <item type="string" name="short_text209" /> + <item type="string" name="short_text210" /> + <item type="string" name="short_text211" /> + <item type="string" name="short_text212" /> + <item type="string" name="short_text213" /> + <item type="string" name="short_text214" /> + <item type="string" name="short_text215" /> + <item type="string" name="short_text216" /> + <item type="string" name="short_text217" /> + <item type="string" name="short_text218" /> + <item type="string" name="short_text219" /> + <item type="string" name="short_text220" /> + <item type="string" name="short_text221" /> + <item type="string" name="short_text222" /> + <item type="string" name="short_text223" /> + <item type="string" name="short_text224" /> + <item type="string" name="short_text225" /> + <item type="string" name="short_text226" /> + <item type="string" name="short_text227" /> + <item type="string" name="short_text228" /> + <item type="string" name="short_text229" /> + <item type="string" name="short_text230" /> + <item type="string" name="short_text231" /> + <item type="string" name="short_text232" /> + <item type="string" name="short_text233" /> + <item type="string" name="short_text234" /> + <item type="string" name="short_text235" /> + <item type="string" name="short_text236" /> + <item type="string" name="short_text237" /> + <item type="string" name="short_text238" /> + <item type="string" name="short_text239" /> + <item type="string" name="short_text240" /> + <item type="string" name="short_text241" /> + <item type="string" name="short_text242" /> + <item type="string" name="short_text243" /> + <item type="string" name="short_text244" /> + <item type="string" name="short_text245" /> + <item type="string" name="short_text246" /> + <item type="string" name="short_text247" /> + <item type="string" name="short_text248" /> + <item type="string" name="short_text249" /> + <item type="string" name="short_text250" /> + <item type="string" name="short_text251" /> + <item type="string" name="short_text252" /> + <item type="string" name="short_text253" /> + <item type="string" name="short_text254" /> + <item type="string" name="short_text255" /> + </policy> + </overlayable> +</resources> diff --git a/apct-tests/perftests/core/res/values/strings.xml b/apct-tests/perftests/core/res/values/strings.xml deleted file mode 100644 index 7ab325f79dc7..000000000000 --- a/apct-tests/perftests/core/res/values/strings.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ 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 - --> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="long_text">text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text typo text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text text text text text - text text text text text text text text text text text text </string> - <string name="short_text">text text</string> -</resources> diff --git a/apct-tests/perftests/core/res/values/values.xml b/apct-tests/perftests/core/res/values/values.xml new file mode 100644 index 000000000000..aad42ba04e11 --- /dev/null +++ b/apct-tests/perftests/core/res/values/values.xml @@ -0,0 +1,368 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="long_text">text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text typo text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text text text text text + text text text text text text text text text text text text </string> + + <plurals name="plurals_text"> + <item quantity="one">1 text</item> + <item quantity="other"><xliff:g id="count" example="3">%d</xliff:g> texts</item> + </plurals> + + <string-array name="strings"> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + <item>Run</item> + <item>the</item> + <item>performance</item> + <item>tests!</item> + </string-array> + + <integer-array name="ints"> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + </integer-array> + + <color name="white">#ffffff</color> + + <integer name="forty_two">42</integer> + + <string name="short_text">text text</string> + <string name="short_text000">B</string> + <string name="short_text001">B</string> + <string name="short_text002">B</string> + <string name="short_text003">B</string> + <string name="short_text004">B</string> + <string name="short_text005">B</string> + <string name="short_text006">B</string> + <string name="short_text007">B</string> + <string name="short_text008">B</string> + <string name="short_text009">B</string> + <string name="short_text010">B</string> + <string name="short_text011">B</string> + <string name="short_text012">B</string> + <string name="short_text013">B</string> + <string name="short_text014">B</string> + <string name="short_text015">B</string> + <string name="short_text016">B</string> + <string name="short_text017">B</string> + <string name="short_text018">B</string> + <string name="short_text019">B</string> + <string name="short_text020">B</string> + <string name="short_text021">B</string> + <string name="short_text022">B</string> + <string name="short_text023">B</string> + <string name="short_text024">B</string> + <string name="short_text025">B</string> + <string name="short_text026">B</string> + <string name="short_text027">B</string> + <string name="short_text028">B</string> + <string name="short_text029">B</string> + <string name="short_text030">B</string> + <string name="short_text031">B</string> + <string name="short_text032">B</string> + <string name="short_text033">B</string> + <string name="short_text034">B</string> + <string name="short_text035">B</string> + <string name="short_text036">B</string> + <string name="short_text037">B</string> + <string name="short_text038">B</string> + <string name="short_text039">B</string> + <string name="short_text040">B</string> + <string name="short_text041">B</string> + <string name="short_text042">B</string> + <string name="short_text043">B</string> + <string name="short_text044">B</string> + <string name="short_text045">B</string> + <string name="short_text046">B</string> + <string name="short_text047">B</string> + <string name="short_text048">B</string> + <string name="short_text049">B</string> + <string name="short_text050">B</string> + <string name="short_text051">B</string> + <string name="short_text052">B</string> + <string name="short_text053">B</string> + <string name="short_text054">B</string> + <string name="short_text055">B</string> + <string name="short_text056">B</string> + <string name="short_text057">B</string> + <string name="short_text058">B</string> + <string name="short_text059">B</string> + <string name="short_text060">B</string> + <string name="short_text061">B</string> + <string name="short_text062">B</string> + <string name="short_text063">B</string> + <string name="short_text064">B</string> + <string name="short_text065">B</string> + <string name="short_text066">B</string> + <string name="short_text067">B</string> + <string name="short_text068">B</string> + <string name="short_text069">B</string> + <string name="short_text070">B</string> + <string name="short_text071">B</string> + <string name="short_text072">B</string> + <string name="short_text073">B</string> + <string name="short_text074">B</string> + <string name="short_text075">B</string> + <string name="short_text076">B</string> + <string name="short_text077">B</string> + <string name="short_text078">B</string> + <string name="short_text079">B</string> + <string name="short_text080">B</string> + <string name="short_text081">B</string> + <string name="short_text082">B</string> + <string name="short_text083">B</string> + <string name="short_text084">B</string> + <string name="short_text085">B</string> + <string name="short_text086">B</string> + <string name="short_text087">B</string> + <string name="short_text088">B</string> + <string name="short_text089">B</string> + <string name="short_text090">B</string> + <string name="short_text091">B</string> + <string name="short_text092">B</string> + <string name="short_text093">B</string> + <string name="short_text094">B</string> + <string name="short_text095">B</string> + <string name="short_text096">B</string> + <string name="short_text097">B</string> + <string name="short_text098">B</string> + <string name="short_text099">B</string> + <string name="short_text100">B</string> + <string name="short_text101">B</string> + <string name="short_text102">B</string> + <string name="short_text103">B</string> + <string name="short_text104">B</string> + <string name="short_text105">B</string> + <string name="short_text106">B</string> + <string name="short_text107">B</string> + <string name="short_text108">B</string> + <string name="short_text109">B</string> + <string name="short_text110">B</string> + <string name="short_text111">B</string> + <string name="short_text112">B</string> + <string name="short_text113">B</string> + <string name="short_text114">B</string> + <string name="short_text115">B</string> + <string name="short_text116">B</string> + <string name="short_text117">B</string> + <string name="short_text118">B</string> + <string name="short_text119">B</string> + <string name="short_text120">B</string> + <string name="short_text121">B</string> + <string name="short_text122">B</string> + <string name="short_text123">B</string> + <string name="short_text124">B</string> + <string name="short_text125">B</string> + <string name="short_text126">B</string> + <string name="short_text127">B</string> + <string name="short_text128">B</string> + <string name="short_text129">B</string> + <string name="short_text130">B</string> + <string name="short_text131">B</string> + <string name="short_text132">B</string> + <string name="short_text133">B</string> + <string name="short_text134">B</string> + <string name="short_text135">B</string> + <string name="short_text136">B</string> + <string name="short_text137">B</string> + <string name="short_text138">B</string> + <string name="short_text139">B</string> + <string name="short_text140">B</string> + <string name="short_text141">B</string> + <string name="short_text142">B</string> + <string name="short_text143">B</string> + <string name="short_text144">B</string> + <string name="short_text145">B</string> + <string name="short_text146">B</string> + <string name="short_text147">B</string> + <string name="short_text148">B</string> + <string name="short_text149">B</string> + <string name="short_text150">B</string> + <string name="short_text151">B</string> + <string name="short_text152">B</string> + <string name="short_text153">B</string> + <string name="short_text154">B</string> + <string name="short_text155">B</string> + <string name="short_text156">B</string> + <string name="short_text157">B</string> + <string name="short_text158">B</string> + <string name="short_text159">B</string> + <string name="short_text160">B</string> + <string name="short_text161">B</string> + <string name="short_text162">B</string> + <string name="short_text163">B</string> + <string name="short_text164">B</string> + <string name="short_text165">B</string> + <string name="short_text166">B</string> + <string name="short_text167">B</string> + <string name="short_text168">B</string> + <string name="short_text169">B</string> + <string name="short_text170">B</string> + <string name="short_text171">B</string> + <string name="short_text172">B</string> + <string name="short_text173">B</string> + <string name="short_text174">B</string> + <string name="short_text175">B</string> + <string name="short_text176">B</string> + <string name="short_text177">B</string> + <string name="short_text178">B</string> + <string name="short_text179">B</string> + <string name="short_text180">B</string> + <string name="short_text181">B</string> + <string name="short_text182">B</string> + <string name="short_text183">B</string> + <string name="short_text184">B</string> + <string name="short_text185">B</string> + <string name="short_text186">B</string> + <string name="short_text187">B</string> + <string name="short_text188">B</string> + <string name="short_text189">B</string> + <string name="short_text190">B</string> + <string name="short_text191">B</string> + <string name="short_text192">B</string> + <string name="short_text193">B</string> + <string name="short_text194">B</string> + <string name="short_text195">B</string> + <string name="short_text196">B</string> + <string name="short_text197">B</string> + <string name="short_text198">B</string> + <string name="short_text199">B</string> + <string name="short_text200">B</string> + <string name="short_text201">B</string> + <string name="short_text202">B</string> + <string name="short_text203">B</string> + <string name="short_text204">B</string> + <string name="short_text205">B</string> + <string name="short_text206">B</string> + <string name="short_text207">B</string> + <string name="short_text208">B</string> + <string name="short_text209">B</string> + <string name="short_text210">B</string> + <string name="short_text211">B</string> + <string name="short_text212">B</string> + <string name="short_text213">B</string> + <string name="short_text214">B</string> + <string name="short_text215">B</string> + <string name="short_text216">B</string> + <string name="short_text217">B</string> + <string name="short_text218">B</string> + <string name="short_text219">B</string> + <string name="short_text220">B</string> + <string name="short_text221">B</string> + <string name="short_text222">B</string> + <string name="short_text223">B</string> + <string name="short_text224">B</string> + <string name="short_text225">B</string> + <string name="short_text226">B</string> + <string name="short_text227">B</string> + <string name="short_text228">B</string> + <string name="short_text229">B</string> + <string name="short_text230">B</string> + <string name="short_text231">B</string> + <string name="short_text232">B</string> + <string name="short_text233">B</string> + <string name="short_text234">B</string> + <string name="short_text235">B</string> + <string name="short_text236">B</string> + <string name="short_text237">B</string> + <string name="short_text238">B</string> + <string name="short_text239">B</string> + <string name="short_text240">B</string> + <string name="short_text241">B</string> + <string name="short_text242">B</string> + <string name="short_text243">B</string> + <string name="short_text244">B</string> + <string name="short_text245">B</string> + <string name="short_text246">B</string> + <string name="short_text247">B</string> + <string name="short_text248">B</string> + <string name="short_text249">B</string> + <string name="short_text250">B</string> + <string name="short_text251">B</string> + <string name="short_text252">B</string> + <string name="short_text253">B</string> + <string name="short_text254">B</string> + <string name="short_text255">B</string> +</resources> diff --git a/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java new file mode 100644 index 000000000000..fcb13a8d51f1 --- /dev/null +++ b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2019 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 android.app; + +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.content.om.OverlayManager; +import android.os.UserHandle; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.TestPackageInstaller; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import com.android.perftests.core.R; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +/** + * Benchmarks for {@link android.content.om.OverlayManager}. + */ +@LargeTest +public class OverlayManagerPerfTest { + private static final int OVERLAY_PKG_COUNT = 10; + private static Context sContext; + private static OverlayManager sOverlayManager; + private static Executor sExecutor; + private static ArrayList<TestPackageInstaller.InstalledPackage> sSmallOverlays = + new ArrayList<>(); + private static ArrayList<TestPackageInstaller.InstalledPackage> sLargeOverlays = + new ArrayList<>(); + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @BeforeClass + public static void classSetUp() throws Exception { + sContext = InstrumentationRegistry.getTargetContext(); + sOverlayManager = new OverlayManager(sContext); + sExecutor = (command) -> new Thread(command).start(); + + // Install all of the test overlays. + TestPackageInstaller installer = new TestPackageInstaller(sContext); + for (int i = 0; i < OVERLAY_PKG_COUNT; i++) { + sSmallOverlays.add(installer.installPackage("Overlay" + i +".apk")); + sLargeOverlays.add(installer.installPackage("LargeOverlay" + i +".apk")); + } + } + + @AfterClass + public static void classTearDown() throws Exception { + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + overlay.uninstall(); + } + + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + overlay.uninstall(); + } + } + + @After + public void tearDown() throws Exception { + // Disable all test overlays after each test. + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), false); + } + + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), false); + } + } + + /** + * Enables the overlay and waits for the APK path change sto be propagated to the context + * AssetManager. + */ + private void assertSetEnabled(Context context, String overlayPackage, boolean eanabled) + throws Exception { + sOverlayManager.setEnabled(overlayPackage, true, UserHandle.SYSTEM); + + // Wait for the overlay changes to propagate + FutureTask<Boolean> task = new FutureTask<>(() -> { + while (true) { + for (String path : context.getAssets().getApkPaths()) { + if (eanabled == path.contains(overlayPackage)) { + return true; + } + } + } + }); + + sExecutor.execute(task); + assertTrue("Failed to load overlay " + overlayPackage, + task.get(20, TimeUnit.SECONDS)); + } + + @Test + public void setEnabledWarmCache() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + state.resumeTiming(); + } + } + + @Test + public void setEnabledColdCacheSmallOverlay() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay and remove the idmap for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM); + state.resumeTiming(); + } + } + + @Test + public void setEnabledColdCacheLargeOverlay() throws Exception { + String packageName = sLargeOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + assertSetEnabled(sContext, packageName, true); + + // Disable the overlay and remove the idmap for the next iteration of the test + state.pauseTiming(); + assertSetEnabled(sContext, packageName, false); + sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM); + state.resumeTiming(); + } + } + + @Test + public void setEnabledDisable() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + assertSetEnabled(sContext, packageName, true); + state.resumeTiming(); + + assertSetEnabled(sContext, packageName, false); + } + } + + @Test + public void getStringOneSmallOverlay() throws Exception { + String packageName = sSmallOverlays.get(0).getPackageName(); + assertSetEnabled(sContext, packageName, true); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + sContext.getString(R.string.short_text); + } + + assertSetEnabled(sContext, packageName, false); + } + + @Test + public void getStringOneLargeOverlay() throws Exception { + String packageName = sLargeOverlays.get(0).getPackageName(); + assertSetEnabled(sContext, packageName, true); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + for (int resId = R.string.short_text000; resId < R.string.short_text255; resId++) { + sContext.getString(resId); + } + } + + assertSetEnabled(sContext, packageName, false); + } + + @Test + public void getStringTenOverlays() throws Exception { + // Enable all test overlays + for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), true); + } + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + sContext.getString(R.string.short_text); + } + } + + @Test + public void getStringLargeTenOverlays() throws Exception { + // Enable all test overlays + for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) { + assertSetEnabled(sContext, overlay.getPackageName(), true); + } + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + for (int resId = R.string.short_text000; resId < R.string.short_text255; resId++) { + sContext.getString(resId); + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java index b3f83596e8a1..a320514dd97a 100644 --- a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.Intent; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -48,7 +48,7 @@ public class PendingIntentPerfTest { @Before public void setUp() { mContext = InstrumentationRegistry.getTargetContext(); - mIntent = StubActivity.createLaunchIntent(mContext); + mIntent = PerfTestActivity.createLaunchIntent(mContext); } /** diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java new file mode 100644 index 000000000000..050fecde8213 --- /dev/null +++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 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 android.app; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.view.Display; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Benchmarks for {@link android.app.ResourcesManager}. + */ +@LargeTest +public class ResourcesManagerPerfTest { + private static Context sContext; + private static File sResourcesCompressed; + private static File sResourcesUncompressed; + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @BeforeClass + public static void setUp() throws Exception { + sContext = InstrumentationRegistry.getTargetContext(); + sResourcesCompressed = copyApkToTemp("LargeResourcesCompressed.apk", + "LargeResourcesCompressed.apk"); + sResourcesUncompressed = copyApkToTemp("LargeResourcesUncompressed.apk", + "LargeResourcesUncompressed.apk"); + } + + @AfterClass + public static void tearDown() { + Assert.assertTrue(sResourcesCompressed.delete()); + Assert.assertTrue(sResourcesUncompressed.delete()); + } + + private static File copyApkToTemp(String inputFileName, String fileName) throws Exception { + File file = File.createTempFile(fileName, null, sContext.getCacheDir()); + try (OutputStream tempOutputStream = new FileOutputStream(file); + InputStream is = sContext.getResources().getAssets().openNonAsset(inputFileName)) { + byte[] buffer = new byte[4096]; + int n; + while ((n = is.read(buffer)) >= 0) { + tempOutputStream.write(buffer, 0, n); + } + tempOutputStream.flush(); + } + return file; + } + + private void getResourcesForPath(String path) { + ResourcesManager.getInstance().getResources(null, path, null, null, null, + Display.DEFAULT_DISPLAY, null, sContext.getResources().getCompatibilityInfo(), + null, null); + } + + @Test + public void getResourcesCached() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + getResourcesForPath(sResourcesCompressed.getPath()); + while (state.keepRunning()) { + getResourcesForPath(sResourcesCompressed.getPath()); + } + } + + @Test + public void getResourcesCompressedUncached() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + resourcesManager.invalidatePath(sResourcesCompressed.getPath()); + state.resumeTiming(); + + getResourcesForPath(sResourcesCompressed.getPath()); + } + } + + @Test + public void getResourcesUncompressedUncached() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + resourcesManager.invalidatePath(sResourcesUncompressed.getPath()); + state.resumeTiming(); + + getResourcesForPath(sResourcesUncompressed.getPath()); + } + } + + @Test + public void applyConfigurationToResourcesLocked() { + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + Configuration c = new Configuration(resourcesManager.getConfiguration()); + c.uiMode = Configuration.UI_MODE_TYPE_WATCH; + + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + resourcesManager.applyConfigurationToResources(c, null); + + // Alternate configurations to ensure the set configuration is different each iteration + if (c.uiMode == Configuration.UI_MODE_TYPE_WATCH) { + c.uiMode = Configuration.UI_MODE_TYPE_TELEVISION; + } else { + c.uiMode = Configuration.UI_MODE_TYPE_WATCH; + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java index c3e43ee07453..72162448a2e0 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java @@ -18,15 +18,18 @@ package android.app; import static org.junit.Assert.fail; -import android.content.res.AssetManager; +import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.util.TypedValue; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import org.junit.After; +import com.android.perftests.core.R; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -43,36 +46,123 @@ public class ResourcesPerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - private AssetManager mAsset; private Resources mRes; - private int mTextId; - private int mColorId; - private int mIntegerId; - private int mLayoutId; - @Before public void setUp() { - mAsset = new AssetManager(); - mAsset.addAssetPath("/system/framework/framework-res.apk"); - mRes = new Resources(mAsset, null, null); + Context context = InstrumentationRegistry.getTargetContext(); + mRes = context.getResources(); + } + + @Test + public void getValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(R.integer.forty_two, value, false /* resolve_refs */); + } + } - mTextId = mRes.getIdentifier("cancel", "string", "android"); - mColorId = mRes.getIdentifier("transparent", "color", "android"); - mIntegerId = mRes.getIdentifier("config_shortAnimTime", "integer", "android"); - mLayoutId = mRes.getIdentifier("two_line_list_item", "layout", "android"); + @Test + public void getFrameworkValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.integer.autofill_max_visible_datasets, value, + false /* resolve_refs */); + } + } + + @Test + public void getValueString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(R.string.long_text, value, false /* resolve_refs */); + } + } + + @Test + public void getFrameworkStringValue() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.string.cancel, value, false /* resolve_refs */); + } } - @After - public void tearDown() { - mAsset.close(); + @Test + public void getValueManyConfigurations() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + TypedValue value = new TypedValue(); + while (state.keepRunning()) { + mRes.getValue(com.android.internal.R.string.mmcc_illegal_me, value, + false /* resolve_refs */); + } } @Test public void getText() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getText(mTextId); + mRes.getText(R.string.long_text); + } + } + + + @Test + public void getFont() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getFont(R.font.samplefont); + } + } + + @Test + public void getString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getString(R.string.long_text); + } + } + + @Test + public void getQuantityString() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getQuantityString(R.plurals.plurals_text, 5); + } + } + + @Test + public void getQuantityText() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getQuantityText(R.plurals.plurals_text, 5); + } + } + + @Test + public void getTextArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getTextArray(R.array.strings); + } + } + + @Test + public void getStringArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getStringArray(R.array.strings); + } + } + + @Test + public void getIntegerArray() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getIntArray(R.array.ints); } } @@ -80,15 +170,23 @@ public class ResourcesPerfTest { public void getColor() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getColor(mColorId, null); + mRes.getColor(R.color.white, null); } } @Test - public void getInteger() { + public void getColorStateList() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - mRes.getInteger(mIntegerId); + mRes.getColorStateList(R.color.color_state_list, null); + } + } + + @Test + public void getVectorDrawable() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + mRes.getDrawable(R.drawable.vector_drawable01, null); } } @@ -96,13 +194,32 @@ public class ResourcesPerfTest { public void getLayoutAndTravese() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - try (XmlResourceParser parser = mRes.getLayout(mLayoutId)) { + try (XmlResourceParser parser = mRes.getLayout(R.layout.test_relative_layout)) { + while (parser.next() != XmlPullParser.END_DOCUMENT) { + // Walk the entire tree + } + } catch (IOException | XmlPullParserException exception) { + fail("Parsing of the layout failed. Something is really broken"); + } + } + } + + @Test + public void getLayoutAndTraverseInvalidateCaches() { + mRes.flushLayoutCache(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + try (XmlResourceParser parser = mRes.getLayout(R.layout.test_relative_layout)) { while (parser.next() != XmlPullParser.END_DOCUMENT) { // Walk the entire tree } } catch (IOException | XmlPullParserException exception) { fail("Parsing of the layout failed. Something is really broken"); } + + state.pauseTiming(); + mRes.flushLayoutCache(); + state.resumeTiming(); } } -} +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java index 1b07572fd3f8..f4c0a172710b 100644 --- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java +++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java @@ -16,13 +16,19 @@ package android.app; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; +import android.os.UserHandle; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; +import android.view.Display; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -35,13 +41,69 @@ public class ResourcesThemePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + private Context mContext; + private int mThemeResId; private Resources.Theme mTheme; @Before - public void setUp() { - Context context = InstrumentationRegistry.getTargetContext(); - mTheme = context.getTheme(); + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + mThemeResId = com.android.perftests.core.R.style.Base_V7_Theme_AppCompat; + mTheme = mContext.getResources().newTheme(); + mTheme.applyStyle(mThemeResId, true /* force */); + } + + @Test + public void applyStyle() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.applyStyle(mThemeResId, true /* force */); + } + } + @Test + public void rebase() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + destTheme.applyStyle(mThemeResId, true /* force */); + destTheme.applyStyle(android.R.style.Theme_Material, true /* force */); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.rebase(); + } + } + + @Test + public void setToSameAssetManager() { + Resources.Theme destTheme = mContext.getResources().newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.setTo(mTheme); + } + } + + @Test + public void setToDifferentAssetManager() throws Exception { + // Create a new Resources object with the same asset paths but a different AssetManager + PackageManager packageManager = mContext.getApplicationContext().getPackageManager(); + ApplicationInfo ai = packageManager.getApplicationInfo(mContext.getPackageName(), + UserHandle.myUserId()); + + ResourcesManager resourcesManager = ResourcesManager.getInstance(); + Configuration c = resourcesManager.getConfiguration(); + c.orientation = (c.orientation == Configuration.ORIENTATION_PORTRAIT) + ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT; + + Resources destResources = resourcesManager.getResources(null, ai.sourceDir, + ai.splitSourceDirs, ai.resourceDirs, ai.sharedLibraryFiles, Display.DEFAULT_DISPLAY, + c, mContext.getResources().getCompatibilityInfo(), null, null); + Assert.assertNotEquals(destResources.getAssets(), mContext.getAssets()); + + Resources.Theme destTheme = destResources.newTheme(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + destTheme.setTo(mTheme); + } } @Test @@ -51,5 +113,4 @@ public class ResourcesThemePerfTest { mTheme.obtainStyledAttributes(android.R.style.Theme_Material, android.R.styleable.View); } } - -} +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java index 3a8002003299..b9c7af46c67c 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java @@ -19,7 +19,7 @@ package android.graphics.perftests; import android.graphics.Paint; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -58,7 +58,8 @@ public class PaintHasGlyphPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java index 3b2b8a94f610..d14e93e553f6 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java @@ -26,7 +26,7 @@ import android.graphics.drawable.VectorDrawable; import android.perftests.utils.BenchmarkState; import android.perftests.utils.BitmapUtils; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.test.suitebuilder.annotation.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -48,8 +48,8 @@ public class VectorDrawablePerfTest { private int[] mTestHeights = {512, 1024}; @Rule - public ActivityTestRule<StubActivity> mActivityRule = - new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java index 3aa6749502bc..236f548cf6dd 100644 --- a/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java @@ -38,7 +38,8 @@ public class PackageManagerPerfTest { private static final String PERMISSION_NAME_DOESNT_EXIST = "com.android.perftests.core.TestBadPermission"; private static final ComponentName TEST_ACTIVITY = - new ComponentName("com.android.perftests.core", "android.perftests.utils.StubActivity"); + new ComponentName("com.android.perftests.core", + "android.perftests.utils.PerfTestActivity"); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java index 5be99d9d779e..6b295e55c9d4 100644 --- a/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java @@ -23,7 +23,7 @@ import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.text.style.ReplacementSpan; import android.util.ArraySet; @@ -75,7 +75,8 @@ public class DynamicLayoutPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java index b34001dcf6b5..b0edb117a00b 100644 --- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java +++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java @@ -23,7 +23,7 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.view.View.MeasureSpec; import android.widget.FrameLayout; import android.widget.ImageView; @@ -46,7 +46,8 @@ import java.util.List; public class ViewShowHidePerfTest { @Rule - public ActivityTestRule mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java index b3ea62aa7da0..270b4e5b49cc 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java @@ -18,7 +18,7 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.text.Selection; import android.view.KeyEvent; import android.view.View.MeasureSpec; @@ -80,7 +80,8 @@ public class EditTextBackspacePerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java index aa47d5bdd998..8028f11be63b 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java @@ -18,7 +18,7 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.text.Selection; import android.view.KeyEvent; import android.view.View.MeasureSpec; @@ -74,7 +74,8 @@ public class EditTextCursorMovementPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java index e50016c45008..f4ad5ddd3ed2 100644 --- a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java @@ -19,7 +19,7 @@ package android.widget; import android.app.Activity; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.view.KeyEvent; import android.view.View.MeasureSpec; import android.view.ViewGroup; @@ -59,7 +59,8 @@ public class EditTextLongTextPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java index 644095b36206..223a3165b1d5 100644 --- a/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java @@ -28,7 +28,7 @@ import android.app.Activity; import android.os.Looper; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import android.view.View; import android.view.ViewGroup; @@ -72,8 +72,8 @@ public class LayoutPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = - new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java index bed173bd269a..694e1f477f89 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java @@ -22,7 +22,7 @@ import android.app.Activity; import android.os.Looper; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -64,8 +64,8 @@ public class TextViewAutoSizeLayoutPerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = - new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java index 00bd8db7f5a3..a5466678167e 100644 --- a/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java +++ b/apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java @@ -18,7 +18,7 @@ package android.widget; import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; -import android.perftests.utils.StubActivity; +import android.perftests.utils.PerfTestActivity; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; @@ -56,7 +56,8 @@ public class TextViewSetTextLocalePerfTest { } @Rule - public ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule(StubActivity.class); + public ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); diff --git a/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java new file mode 100644 index 000000000000..4ed3b4e09d11 --- /dev/null +++ b/apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2019 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 android.wm; + +import static android.perftests.utils.ManualBenchmarkState.StatsReport; + +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.perftests.utils.ManualBenchmarkState; +import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest; +import android.perftests.utils.PerfManualStatusReporter; +import android.perftests.utils.TraceMarkParser; +import android.perftests.utils.TraceMarkParser.TraceMarkSlice; +import android.util.Log; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.lifecycle.Stage; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.concurrent.TimeUnit; + +/** Measure the performance of internal methods in window manager service by trace tag. */ +@LargeTest +public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase { + private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName(); + + @Rule + public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); + + @Rule + public final PerfTestActivityRule mActivityRule = new PerfTestActivityRule(); + + private final TraceMarkParser mTraceMarkParser = new TraceMarkParser( + "applyPostLayoutPolicy", + "applySurfaceChanges", + "AppTransitionReady", + "closeSurfaceTransactiom", + "openSurfaceTransaction", + "performLayout", + "performSurfacePlacement", + "prepareSurfaces", + "updateInputWindows", + "WSA#startAnimation", + "activityIdle", + "activityPaused", + "activityStopped", + "activityDestroyed", + "finishActivity", + "startActivityInner"); + + @Test + @ManualBenchmarkTest( + targetTestDurationNs = 20 * TIME_1_S_IN_NS, + statsReport = @StatsReport( + flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN + | StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR)) + public void testLaunchAndFinishActivity() throws Throwable { + final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + long measuredTimeNs = 0; + boolean isTraceStarted = false; + + while (state.keepRunning(measuredTimeNs)) { + if (!isTraceStarted && !state.isWarmingUp()) { + startAsyncAtrace(); + isTraceStarted = true; + } + final long startTime = SystemClock.elapsedRealtimeNanos(); + mActivityRule.launchActivity(); + mActivityRule.finishActivity(); + mActivityRule.waitForIdleSync(Stage.DESTROYED); + measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; + } + + stopAsyncAtrace(); + + mTraceMarkParser.forAllSlices((key, slices) -> { + for (TraceMarkSlice slice : slices) { + state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S)); + } + }); + + Log.i(TAG, String.valueOf(mTraceMarkParser)); + } + + private void startAsyncAtrace() throws IOException { + sUiAutomation.executeShellCommand("atrace -b 32768 --async_start wm"); + // Avoid atrace isn't ready immediately. + SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS)); + } + + private void stopAsyncAtrace() throws IOException { + final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop"); + final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + mTraceMarkParser.visit(line); + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java new file mode 100644 index 000000000000..73b4a1914ad1 --- /dev/null +++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 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 android.wm; + +import static android.perftests.utils.ManualBenchmarkState.StatsReport; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.hamcrest.core.AnyOf.anyOf; +import static org.hamcrest.core.Is.is; + +import android.app.ActivityManager.TaskSnapshot; +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Rect; +import android.os.RemoteException; +import android.os.SystemClock; +import android.perftests.utils.ManualBenchmarkState; +import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest; +import android.perftests.utils.PerfManualStatusReporter; +import android.util.Pair; +import android.view.IRecentsAnimationController; +import android.view.IRecentsAnimationRunner; +import android.view.RemoteAnimationTarget; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.lifecycle.Stage; + +import org.junit.AfterClass; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +@RunWith(Parameterized.class) +@LargeTest +public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { + private static Intent sRecentsIntent; + + @Rule + public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); + + @Rule + public final PerfTestActivityRule mActivityRule = + new PerfTestActivityRule(true /* launchActivity */); + + private long mMeasuredTimeNs; + + @Parameterized.Parameter(0) + public int intervalBetweenOperations; + + @Parameterized.Parameters(name = "interval{0}ms") + public static Collection<Object[]> getParameters() { + return Arrays.asList(new Object[][] { + { 0 }, + { 100 }, + { 300 }, + }); + } + + @BeforeClass + public static void setUpClass() { + // Get the permission to invoke startRecentsActivity. + sUiAutomation.adoptShellPermissionIdentity(); + + final Context context = getInstrumentation().getContext(); + final PackageManager pm = context.getPackageManager(); + final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>()); + + try { + final ComponentName recentsComponent = + ComponentName.unflattenFromString(context.getResources().getString( + com.android.internal.R.string.config_recentsComponentName)); + final int enabledState = pm.getComponentEnabledSetting(recentsComponent); + Assume.assumeThat(enabledState, anyOf( + is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED))); + + final boolean homeIsRecents = + recentsComponent.getPackageName().equals(defaultHome.getPackageName()); + sRecentsIntent = + new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent); + } catch (Exception e) { + Assume.assumeNoException(e); + } + } + + @AfterClass + public static void tearDownClass() { + sUiAutomation.dropShellPermissionIdentity(); + } + + /** Simulate the timing of touch. */ + private void makeInterval() { + SystemClock.sleep(intervalBetweenOperations); + } + + /** + * <pre> + * Steps: + * (1) Start recents activity (only make it visible). + * (2) Finish animation, take turns to execute (a), (b). + * (a) Move recents activity to top. + * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP}) + * Move test app to top by startActivityFromRecents. + * (b) Cancel (it is similar to swipe a little distance and give up to enter recents). + * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION}) + * (3) Loop (1). + * </pre> + */ + @Test + @ManualBenchmarkTest( + warmupDurationNs = TIME_1_S_IN_NS, + targetTestDurationNs = TIME_5_S_IN_NS, + statsReport = @StatsReport(flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN + | StatsReport.FLAG_COEFFICIENT_VAR)) + public void testRecentsAnimation() throws Throwable { + final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final IActivityTaskManager atm = ActivityTaskManager.getService(); + + final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>(); + // Real launch the recents activity. + finishCases.add(new Pair<>("finishMoveToTop", true)); + // Return to the original top. + finishCases.add(new Pair<>("finishCancel", false)); + + // Ensure startRecentsActivity won't be called before finishing the animation. + final Semaphore recentsSemaphore = new Semaphore(1); + + final int testActivityTaskId = mActivityRule.getActivity().getTaskId(); + final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() { + int mIteration; + + @Override + public void onAnimationStart(IRecentsAnimationController controller, + RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, + Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException { + final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2); + final boolean moveRecentsToTop = finishCase.second; + makeInterval(); + + long startTime = SystemClock.elapsedRealtimeNanos(); + controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */); + final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime; + mMeasuredTimeNs += elapsedTimeNsOfFinish; + state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish); + + if (moveRecentsToTop) { + mActivityRule.waitForIdleSync(Stage.STOPPED); + + startTime = SystemClock.elapsedRealtimeNanos(); + atm.startActivityFromRecents(testActivityTaskId, null /* options */); + final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; + mMeasuredTimeNs += elapsedTimeNs; + state.addExtraResult("startFromRecents", elapsedTimeNs); + + mActivityRule.waitForIdleSync(Stage.RESUMED); + } + + makeInterval(); + recentsSemaphore.release(); + } + + @Override + public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException { + Assume.assumeNoException( + new AssertionError("onAnimationCanceled should not be called")); + } + }; + + recentsSemaphore.tryAcquire(); + while (state.keepRunning(mMeasuredTimeNs)) { + mMeasuredTimeNs = 0; + + final long startTime = SystemClock.elapsedRealtimeNanos(); + atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim); + final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime; + mMeasuredTimeNs += elapsedTimeNsOfStart; + state.addExtraResult("start", elapsedTimeNsOfStart); + + // Ensure the animation callback is done. + Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); + } + } +} diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java new file mode 100644 index 000000000000..b6e39e14602a --- /dev/null +++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2019 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 android.wm; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.RemoteException; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.perftests.utils.PerfTestActivity; +import android.util.MergedConfiguration; +import android.view.DisplayCutout; +import android.view.IWindow; +import android.view.IWindowSession; +import android.view.InsetsState; +import android.view.SurfaceControl; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.widget.LinearLayout; + +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.IntSupplier; + +@RunWith(Parameterized.class) +@LargeTest +public class RelayoutPerfTest extends WindowManagerPerfTestBase { + private int mIteration; + + @Rule + public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Rule + public final ActivityTestRule<PerfTestActivity> mActivityRule = + new ActivityTestRule<>(PerfTestActivity.class); + + /** This is only a placement to match the input parameters from {@link #getParameters}. */ + @Parameterized.Parameter(0) + public String testName; + + /** The visibilities to loop for relayout. */ + @Parameterized.Parameter(1) + public int[] visibilities; + + /** + * Each row will be mapped into {@link #testName} and {@link #visibilities} of a new test + * instance according to the index of the parameter. + */ + @Parameterized.Parameters(name = "{0}") + public static Collection<Object[]> getParameters() { + return Arrays.asList(new Object[][] { + { "Visible", new int[] { View.VISIBLE } }, + { "Invisible~Visible", new int[] { View.INVISIBLE, View.VISIBLE } }, + { "Gone~Visible", new int[] { View.GONE, View.VISIBLE } }, + { "Gone~Invisible", new int[] { View.GONE, View.INVISIBLE } } + }); + } + + @Test + public void testRelayout() throws Throwable { + final Activity activity = mActivityRule.getActivity(); + final ContentView contentView = new ContentView(activity); + mActivityRule.runOnUiThread(() -> { + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + activity.setContentView(contentView); + }); + getInstrumentation().waitForIdleSync(); + + final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(), + () -> visibilities[mIteration++ % visibilities.length]); + relayoutRunner.runBenchmark(mPerfStatusReporter.getBenchmarkState()); + } + + /** A dummy view to get IWindow. */ + private static class ContentView extends LinearLayout { + ContentView(Context context) { + super(context); + } + + @Override + protected IWindow getWindow() { + return super.getWindow(); + } + } + + private static class RelayoutRunner { + final Rect mOutFrame = new Rect(); + final Rect mOutContentInsets = new Rect(); + final Rect mOutVisibleInsets = new Rect(); + final Rect mOutStableInsets = new Rect(); + final Rect mOutBackDropFrame = new Rect(); + final DisplayCutout.ParcelableWrapper mOutDisplayCutout = + new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); + final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration(); + final InsetsState mOutInsetsState = new InsetsState(); + final IWindow mWindow; + final View mView; + final WindowManager.LayoutParams mParams; + final int mWidth; + final int mHeight; + final SurfaceControl mOutSurfaceControl; + + final IntSupplier mViewVisibility; + + int mSeq; + int mFrameNumber; + int mFlags; + + RelayoutRunner(Activity activity, IWindow window, IntSupplier visibilitySupplier) { + mWindow = window; + mView = activity.getWindow().getDecorView(); + mParams = (WindowManager.LayoutParams) mView.getLayoutParams(); + mWidth = mView.getMeasuredWidth(); + mHeight = mView.getMeasuredHeight(); + mOutSurfaceControl = mView.getViewRootImpl().getSurfaceControl(); + mViewVisibility = visibilitySupplier; + } + + void runBenchmark(BenchmarkState state) throws RemoteException { + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + while (state.keepRunning()) { + session.relayout(mWindow, mSeq, mParams, mWidth, mHeight, + mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame, + mOutContentInsets, mOutVisibleInsets, mOutStableInsets, + mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration, + mOutSurfaceControl, mOutInsetsState, new Point(), new SurfaceControl()); + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java new file mode 100644 index 000000000000..4ac3adfd19ce --- /dev/null +++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 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 android.wm; + +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + +import android.graphics.Rect; +import android.os.RemoteException; +import android.os.SystemClock; +import android.perftests.utils.ManualBenchmarkState; +import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest; +import android.perftests.utils.PerfManualStatusReporter; +import android.view.Display; +import android.view.DisplayCutout; +import android.view.IWindowSession; +import android.view.InputChannel; +import android.view.InsetsState; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; + +import androidx.test.filters.LargeTest; + +import com.android.internal.view.BaseIWindow; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +@LargeTest +public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase + implements ManualBenchmarkState.CustomizedIterationListener { + + private static final int PROFILED_ITERATIONS = 2; + + @Rule + public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); + + @BeforeClass + public static void setUpClass() { + // Get the permission to use most window types. + sUiAutomation.adoptShellPermissionIdentity(); + } + + @AfterClass + public static void tearDownClass() { + sUiAutomation.dropShellPermissionIdentity(); + } + + /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */ + @Override + public void onStart(int iteration) { + startProfiling(WindowAddRemovePerfTest.class.getSimpleName() + + "_MethodTracing_" + iteration + ".trace"); + } + + @Override + public void onFinished(int iteration) { + stopProfiling(); + } + + @Test + @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS) + public void testAddRemoveWindow() throws Throwable { + final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + state.setCustomizedIterations(PROFILED_ITERATIONS, this); + new TestWindow().runBenchmark(state); + } + + private static class TestWindow extends BaseIWindow { + final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); + final Rect mOutFrame = new Rect(); + final Rect mOutContentInsets = new Rect(); + final Rect mOutStableInsets = new Rect(); + final DisplayCutout.ParcelableWrapper mOutDisplayCutout = + new DisplayCutout.ParcelableWrapper(); + final InsetsState mOutInsetsState = new InsetsState(); + + TestWindow() { + mLayoutParams.setTitle(TestWindow.class.getName()); + mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + // Simulate as common phone window. + mLayoutParams.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR; + } + + void runBenchmark(ManualBenchmarkState state) throws RemoteException { + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + long elapsedTimeNs = 0; + while (state.keepRunning(elapsedTimeNs)) { + // InputChannel cannot be reused. + final InputChannel inputChannel = new InputChannel(); + + long startTime = SystemClock.elapsedRealtimeNanos(); + session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE, + Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets, + mOutDisplayCutout, inputChannel, mOutInsetsState); + final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime; + state.addExtraResult("add", elapsedTimeNsOfAdd); + + startTime = SystemClock.elapsedRealtimeNanos(); + session.remove(this); + final long elapsedTimeNsOfRemove = SystemClock.elapsedRealtimeNanos() - startTime; + state.addExtraResult("remove", elapsedTimeNsOfRemove); + + elapsedTimeNs = elapsedTimeNsOfAdd + elapsedTimeNsOfRemove; + inputChannel.dispose(); + } + } + } +} diff --git a/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java new file mode 100644 index 000000000000..62e9ba84530c --- /dev/null +++ b/apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2019 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 android.wm; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import android.app.Activity; +import android.app.UiAutomation; +import android.content.Intent; +import android.os.ParcelFileDescriptor; +import android.perftests.utils.PerfTestActivity; + +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.lifecycle.ActivityLifecycleCallback; +import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; +import androidx.test.runner.lifecycle.Stage; + +import org.junit.BeforeClass; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public class WindowManagerPerfTestBase { + static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation(); + static final long NANOS_PER_S = 1000L * 1000 * 1000; + static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; + static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; + + /** + * The out directory matching the directory-keys of collector in AndroidTest.xml. The directory + * is in /data because while enabling method profling of system server, it cannot write the + * trace to external storage. + */ + static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests"); + + @BeforeClass + public static void setUpOnce() { + if (!BASE_OUT_PATH.exists()) { + executeShellCommand("mkdir -p " + BASE_OUT_PATH); + } + // In order to be closer to the real use case. + executeShellCommand("input keyevent KEYCODE_WAKEUP"); + executeShellCommand("wm dismiss-keyguard"); + getInstrumentation().getContext().startActivity(new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + /** + * Executes shell command with reading the output. It may also used to block until the current + * command is completed. + */ + static ByteArrayOutputStream executeShellCommand(String command) { + final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand(command); + final byte[] buf = new byte[512]; + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + int bytesRead; + try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + while ((bytesRead = fis.read(buf)) != -1) { + bytes.write(buf, 0, bytesRead); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return bytes; + } + + /** Starts method tracing on system server. */ + void startProfiling(String subPath) { + executeShellCommand("am profile start system " + new File(BASE_OUT_PATH, subPath)); + } + + void stopProfiling() { + executeShellCommand("am profile stop system"); + } + + /** + * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage. + */ + static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> { + private final Intent mStartIntent = + new Intent().putExtra(PerfTestActivity.INTENT_EXTRA_KEEP_SCREEN_ON, true); + private final LifecycleListener mLifecycleListener = new LifecycleListener(); + + PerfTestActivityRule() { + this(false /* launchActivity */); + } + + PerfTestActivityRule(boolean launchActivity) { + super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity); + } + + @Override + public Statement apply(Statement base, Description description) { + final Statement wrappedStatement = new Statement() { + @Override + public void evaluate() throws Throwable { + ActivityLifecycleMonitorRegistry.getInstance() + .addLifecycleCallback(mLifecycleListener); + base.evaluate(); + ActivityLifecycleMonitorRegistry.getInstance() + .removeLifecycleCallback(mLifecycleListener); + } + }; + return super.apply(wrappedStatement, description); + } + + @Override + protected Intent getActivityIntent() { + return mStartIntent; + } + + @Override + public PerfTestActivity launchActivity(Intent intent) { + final PerfTestActivity activity = super.launchActivity(intent); + mLifecycleListener.setTargetActivity(activity); + return activity; + } + + PerfTestActivity launchActivity() { + return launchActivity(mStartIntent); + } + + void waitForIdleSync(Stage state) { + mLifecycleListener.waitForIdleSync(state); + } + } + + static class LifecycleListener implements ActivityLifecycleCallback { + private Activity mTargetActivity; + private Stage mWaitingStage; + private Stage mReceivedStage; + + void setTargetActivity(Activity activity) { + mTargetActivity = activity; + mReceivedStage = mWaitingStage = null; + } + + void waitForIdleSync(Stage stage) { + synchronized (this) { + if (stage != mReceivedStage) { + mWaitingStage = stage; + try { + wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS)); + } catch (InterruptedException impossible) { } + } + mWaitingStage = mReceivedStage = null; + } + getInstrumentation().waitForIdleSync(); + } + + @Override + public void onActivityLifecycleChanged(Activity activity, Stage stage) { + if (mTargetActivity != activity) { + return; + } + + synchronized (this) { + mReceivedStage = stage; + if (mWaitingStage == mReceivedStage) { + notifyAll(); + } + } + } + } +} diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml index e96771cf1c17..893c8ca9328b 100644 --- a/apct-tests/perftests/multiuser/AndroidManifest.xml +++ b/apct-tests/perftests/multiuser/AndroidManifest.xml @@ -17,9 +17,12 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.perftests.multiuser"> + <uses-permission android:name="android.permission.CONTROL_KEYGUARD" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/apct-tests/perftests/multiuser/AndroidTest.xml b/apct-tests/perftests/multiuser/AndroidTest.xml index 512dbc9a8de7..9117561fe1e5 100644 --- a/apct-tests/perftests/multiuser/AndroidTest.xml +++ b/apct-tests/perftests/multiuser/AndroidTest.xml @@ -19,6 +19,7 @@ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="MultiUserPerfTests.apk" /> + <option name="test-file-name" value="MultiUserPerfDummyApp.apk" /> </target_preparer> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > diff --git a/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp new file mode 100644 index 000000000000..08c54a60a290 --- /dev/null +++ b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp @@ -0,0 +1,21 @@ +// Copyright (C) 2019 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. + +android_test_helper_app { + name: "MultiUserPerfDummyApp", + + srcs: ["src/**/*.java"], + + sdk_version: "test_current", +} diff --git a/apct-tests/perftests/multiuser/apps/dummyapp/AndroidManifest.xml b/apct-tests/perftests/multiuser/apps/dummyapp/AndroidManifest.xml new file mode 100644 index 000000000000..d4d37f97b00a --- /dev/null +++ b/apct-tests/perftests/multiuser/apps/dummyapp/AndroidManifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="perftests.multiuser.apps.dummyapp" > + + <application android:label="Perftest Multiuser Dummy App"> + + <activity + android:name=".DummyForegroundActivity" + android:label="Perftest Multiuser Dummy App" + android:exported="true" + android:launchMode="singleTop" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + +</manifest>
\ No newline at end of file diff --git a/apct-tests/perftests/multiuser/apps/dummyapp/src/com/android/multiuser/test/DummyForegroundActivity.java b/apct-tests/perftests/multiuser/apps/dummyapp/src/com/android/multiuser/test/DummyForegroundActivity.java new file mode 100644 index 000000000000..497d242b2531 --- /dev/null +++ b/apct-tests/perftests/multiuser/apps/dummyapp/src/com/android/multiuser/test/DummyForegroundActivity.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 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 perftests.multiuser.apps.dummyapp; + +import android.app.Activity; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.SystemClock; + +/** An activity. */ +public class DummyForegroundActivity extends Activity { + private static final String TAG = DummyForegroundActivity.class.getSimpleName(); + + public static final int TOP_SLEEP_TIME_MS = 2_000; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + doSleepWhileTop(TOP_SLEEP_TIME_MS); + } + + /** Does nothing, but asynchronously. */ + private void doSleepWhileTop(int sleepTime) { + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + SystemClock.sleep(sleepTime); + return null; + } + + @Override + protected void onPostExecute(Void nothing) { + finish(); + } + }.execute(); + } +} diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index c121bd9caa57..661f32f35cb2 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -15,19 +15,35 @@ */ package android.multiuser; +import static org.junit.Assume.assumeTrue; + import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.AppGlobals; import android.app.IActivityManager; import android.app.IStopUserCallback; import android.app.UserSwitchObserver; +import android.app.WaitResult; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.IIntentReceiver; +import android.content.IIntentSender; import android.content.Intent; import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.pm.IPackageInstaller; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.IBinder; +import android.os.IProgressListener; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.perftests.utils.ShellHelper; import android.util.Log; +import android.view.WindowManagerGlobal; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -66,13 +82,25 @@ import java.util.concurrent.TimeUnit; public class UserLifecycleTests { private static final String TAG = UserLifecycleTests.class.getSimpleName(); - private final int TIMEOUT_IN_SECOND = 30; - private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; + private static final int TIMEOUT_IN_SECOND = 30; + private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200; + + private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp"; + + // Copy of UserSystemPackageInstaller whitelist mode constants. + private static final String PACKAGE_WHITELIST_MODE_PROP = + "persist.debug.user.package_whitelist_mode"; + private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0; + private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001; + private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100; + private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1; private UserManager mUm; private ActivityManager mAm; private IActivityManager mIam; + private PackageManager mPm; private ArrayList<Integer> mUsersToRemove; + private boolean mHasManagedUserFeature; private final BenchmarkRunner mRunner = new BenchmarkRunner(); @Rule @@ -85,6 +113,8 @@ public class UserLifecycleTests { mAm = context.getSystemService(ActivityManager.class); mIam = ActivityManager.getService(); mUsersToRemove = new ArrayList<>(); + mPm = context.getPackageManager(); + mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS); } @After @@ -99,34 +129,89 @@ public class UserLifecycleTests { } @Test + public void createUser() { + while (mRunner.keepRunning()) { + final int userId = createUserNoFlags(); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + @Test public void createAndStartUser() throws Exception { while (mRunner.keepRunning()) { - final UserInfo userInfo = mUm.createUser("TestUser", 0); + final int userId = createUserNoFlags(); + + final CountDownLatch latch = new CountDownLatch(1); + registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId); + // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until + // ACTION_USER_STARTED. + mIam.startUserInBackground(userId); + latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + /** + * Measures the time until ACTION_USER_STARTED is received. + */ + @Test + public void startUser() throws Exception { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id); - mIam.startUserInBackground(userInfo.id); + registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId); + mRunner.resumeTiming(); + + mIam.startUserInBackground(userId); latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); mRunner.pauseTiming(); - removeUser(userInfo.id); + removeUser(userId); mRunner.resumeTiming(); } } + /** + * Measures the time until unlock listener is triggered and user is unlocked. + */ + @Test + public void startAndUnlockUser() throws Exception { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createUserNoFlags(); + mRunner.resumeTiming(); + + // Waits for UserState.mUnlockProgress.finish(). + startUserInBackgroundAndWaitForUnlock(userId); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + + @Test public void switchUser() throws Exception { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); - final UserInfo userInfo = mUm.createUser("TestUser", 0); + final int userId = createUserNoFlags(); mRunner.resumeTiming(); - switchUser(userInfo.id); + switchUser(userId); mRunner.pauseTiming(); switchUser(startUser); - removeUser(userInfo.id); + removeUser(userId); mRunner.resumeTiming(); } } @@ -176,17 +261,17 @@ public class UserLifecycleTests { public void stopUser() throws Exception { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final UserInfo userInfo = mUm.createUser("TestUser", 0); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userInfo.id); - mIam.startUserInBackground(userInfo.id); + registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId); + mIam.startUserInBackground(userId); latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); mRunner.resumeTiming(); - stopUser(userInfo.id, false); + stopUser(userId, false); mRunner.pauseTiming(); - removeUser(userInfo.id); + removeUser(userId); mRunner.resumeTiming(); } } @@ -196,120 +281,311 @@ public class UserLifecycleTests { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int startUser = mAm.getCurrentUser(); - final UserInfo userInfo = mUm.createUser("TestUser", 0); + final int userId = createUserNoFlags(); final CountDownLatch latch = new CountDownLatch(1); - registerUserSwitchObserver(null, latch, userInfo.id); + registerUserSwitchObserver(null, latch, userId); mRunner.resumeTiming(); - mAm.switchUser(userInfo.id); + mAm.switchUser(userId); latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); mRunner.pauseTiming(); switchUser(startUser); - removeUser(userInfo.id); + removeUser(userId); mRunner.resumeTiming(); } } @Test - public void managedProfileUnlock() throws Exception { + public void ephemeralUserStopped() throws Exception { while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final UserInfo userInfo = mUm.createProfileForUser("TestUser", - UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); + final int startUser = mAm.getCurrentUser(); + final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO); + switchUser(userId); final CountDownLatch latch = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id); + InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra( + Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) { + latch.countDown(); + } + } + }, new IntentFilter(Intent.ACTION_USER_STOPPED)); + final CountDownLatch switchLatch = new CountDownLatch(1); + registerUserSwitchObserver(switchLatch, null, startUser); mRunner.resumeTiming(); - mIam.startUserInBackground(userInfo.id); + mAm.switchUser(startUser); latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); mRunner.pauseTiming(); - removeUser(userInfo.id); + switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + /** Tests creating a new profile. */ + @Test + public void managedProfileCreate() throws Exception { + assumeTrue(mHasManagedUserFeature); + + while (mRunner.keepRunning()) { + final int userId = createManagedProfile(); + + mRunner.pauseTiming(); + attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId)); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + /** Tests starting (unlocking) a newly-created profile. */ + @Test + public void managedProfileUnlock() throws Exception { + assumeTrue(mHasManagedUserFeature); + + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createManagedProfile(); + mRunner.resumeTiming(); + + startUserInBackgroundAndWaitForUnlock(userId); + + mRunner.pauseTiming(); + removeUser(userId); mRunner.resumeTiming(); } } - /** Tests starting an already-created, but no-longer-running, profile. */ + /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */ @Test public void managedProfileUnlock_stopped() throws Exception { + assumeTrue(mHasManagedUserFeature); + while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final UserInfo userInfo = mUm.createProfileForUser("TestUser", - UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); + final int userId = createManagedProfile(); // Start the profile initially, then stop it. Similar to setQuietModeEnabled. - final CountDownLatch latch1 = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, userInfo.id); - mIam.startUserInBackground(userInfo.id); - latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); - stopUser(userInfo.id, true); + startUserInBackgroundAndWaitForUnlock(userId); + stopUser(userId, true); + mRunner.resumeTiming(); - // Now we restart the profile. - final CountDownLatch latch2 = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch2, userInfo.id); + startUserInBackgroundAndWaitForUnlock(userId); + + mRunner.pauseTiming(); + removeUser(userId); mRunner.resumeTiming(); + } + } - mIam.startUserInBackground(userInfo.id); - latch2.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + /** + * Tests starting (unlocking) and launching an already-installed app in a newly-created profile. + */ + @Test + public void managedProfileUnlockAndLaunchApp() throws Exception { + assumeTrue(mHasManagedUserFeature); + while (mRunner.keepRunning()) { mRunner.pauseTiming(); - removeUser(userInfo.id); + final int userId = createManagedProfile(); + WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null); + installPreexistingApp(userId, DUMMY_PACKAGE_NAME); + mRunner.resumeTiming(); + + startUserInBackgroundAndWaitForUnlock(userId); + startApp(userId, DUMMY_PACKAGE_NAME); + + mRunner.pauseTiming(); + removeUser(userId); mRunner.resumeTiming(); } } + /** + * Tests starting (unlocking) and launching a previously-launched app + * in an already-created, but no-longer-running, profile. + * A sort of combination of {@link #managedProfileUnlockAndLaunchApp} and + * {@link #managedProfileUnlock_stopped}}. + */ @Test - public void ephemeralUserStopped() throws Exception { + public void managedProfileUnlockAndLaunchApp_stopped() throws Exception { + assumeTrue(mHasManagedUserFeature); + while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final int startUser = mAm.getCurrentUser(); - final UserInfo userInfo = mUm.createUser("TestUser", - UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO); - switchUser(userInfo.id); - final CountDownLatch latch = new CountDownLatch(1); - InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra( - Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userInfo.id) { - latch.countDown(); - } - } - }, new IntentFilter(Intent.ACTION_USER_STOPPED)); - final CountDownLatch switchLatch = new CountDownLatch(1); - registerUserSwitchObserver(switchLatch, null, startUser); + final int userId = createManagedProfile(); + WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null); + installPreexistingApp(userId, DUMMY_PACKAGE_NAME); + startUserInBackgroundAndWaitForUnlock(userId); + startApp(userId, DUMMY_PACKAGE_NAME); + stopUser(userId, true); + TimeUnit.SECONDS.sleep(1); // Brief cool-down before re-starting profile. mRunner.resumeTiming(); - mAm.switchUser(startUser); - latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + startUserInBackgroundAndWaitForUnlock(userId); + startApp(userId, DUMMY_PACKAGE_NAME); mRunner.pauseTiming(); - switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); - removeUser(userInfo.id); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + /** Tests installing a pre-existing app in a newly-created profile. */ + @Test + public void managedProfileInstall() throws Exception { + assumeTrue(mHasManagedUserFeature); + + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createManagedProfile(); + mRunner.resumeTiming(); + + installPreexistingApp(userId, DUMMY_PACKAGE_NAME); + + mRunner.pauseTiming(); + removeUser(userId); mRunner.resumeTiming(); } } + /** + * Tests creating a new profile, starting (unlocking) it, installing an app, + * and launching that app in it. + */ + @Test + public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception { + assumeTrue(mHasManagedUserFeature); + + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + WindowManagerGlobal.getWindowManagerService().dismissKeyguard(null, null); + mRunner.resumeTiming(); + + final int userId = createManagedProfile(); + startUserInBackgroundAndWaitForUnlock(userId); + installPreexistingApp(userId, DUMMY_PACKAGE_NAME); + startApp(userId, DUMMY_PACKAGE_NAME); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } + + /** Tests stopping a profile. */ @Test public void managedProfileStopped() throws Exception { + assumeTrue(mHasManagedUserFeature); + while (mRunner.keepRunning()) { mRunner.pauseTiming(); - final UserInfo userInfo = mUm.createProfileForUser("TestUser", - UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); - final CountDownLatch latch = new CountDownLatch(1); - registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, userInfo.id); - mIam.startUserInBackground(userInfo.id); - latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + final int userId = createManagedProfile(); + startUserInBackgroundAndWaitForUnlock(userId); mRunner.resumeTiming(); - stopUser(userInfo.id, true); + stopUser(userId, true); mRunner.pauseTiming(); - removeUser(userInfo.id); + removeUser(userId); mRunner.resumeTiming(); } } + // TODO: This is just a POC. Do this properly and add more. + /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */ + @Test + public void managedProfileUnlock_usingWhitelist() throws Exception { + assumeTrue(mHasManagedUserFeature); + final int origMode = getUserTypePackageWhitelistMode(); + setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE + | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST); + + try { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createManagedProfile(); + mRunner.resumeTiming(); + + startUserInBackgroundAndWaitForUnlock(userId); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } finally { + setUserTypePackageWhitelistMode(origMode); + } + } + /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */ + @Test + public void managedProfileUnlock_notUsingWhitelist() throws Exception { + assumeTrue(mHasManagedUserFeature); + final int origMode = getUserTypePackageWhitelistMode(); + setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE); + + try { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int userId = createManagedProfile(); + mRunner.resumeTiming(); + + startUserInBackgroundAndWaitForUnlock(userId); + + mRunner.pauseTiming(); + removeUser(userId); + mRunner.resumeTiming(); + } + } finally { + setUserTypePackageWhitelistMode(origMode); + } + } + + /** Creates a new user, returning its userId. */ + private int createUserNoFlags() { + return createUserWithFlags(/* flags= */ 0); + } + + /** Creates a new user with the given flags, returning its userId. */ + private int createUserWithFlags(int flags) { + int userId = mUm.createUser("TestUser", flags).id; + mUsersToRemove.add(userId); + return userId; + } + + /** Creates a managed (work) profile under the current user, returning its userId. */ + private int createManagedProfile() { + final UserInfo userInfo = mUm.createProfileForUser("TestProfile", + UserManager.USER_TYPE_PROFILE_MANAGED, /* flags */ 0, mAm.getCurrentUser()); + if (userInfo == null) { + throw new IllegalStateException("Creating managed profile failed. Most likely there is " + + "already a pre-existing profile on the device."); + } + mUsersToRemove.add(userInfo.id); + return userInfo.id; + } + + /** + * Start user in background and wait for it to unlock by waiting for + * UserState.mUnlockProgress.finish(). + * <p> To start in foreground instead, see {@link #switchUser(int)}. + * <p> This should always be used for profiles since profiles cannot be started in foreground. + */ + private void startUserInBackgroundAndWaitForUnlock(int userId) { + final ProgressWaiter waiter = new ProgressWaiter(); + try { + mIam.startUserInBackgroundWithListener(userId, waiter); + boolean success = waiter.waitForFinish(TIMEOUT_IN_SECOND); + attestTrue("Failed to start user " + userId + " in background.", success); + } catch (RemoteException e) { + Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e); + } + } + + /** Starts the given user in the foreground. */ private void switchUser(int userId) throws Exception { final CountDownLatch latch = new CountDownLatch(1); registerUserSwitchObserver(latch, null, userId); @@ -342,7 +618,7 @@ public class UserLifecycleTests { private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception { final int origUser = mAm.getCurrentUser(); // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED - final int testUser = mUm.createUser("TestUser", 0).id; + final int testUser = createUserNoFlags(); final CountDownLatch latch1 = new CountDownLatch(1); registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser); mAm.switchUser(testUser); @@ -361,6 +637,46 @@ public class UserLifecycleTests { return testUser; } + /** + * Installs the given package in the given user. + */ + private void installPreexistingApp(int userId, String packageName) throws RemoteException { + final CountDownLatch latch = new CountDownLatch(1); + + final IntentSender sender = new IntentSender((IIntentSender) new IIntentSender.Stub() { + @Override + public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, + IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { + latch.countDown(); + } + }); + + final IPackageInstaller installer = AppGlobals.getPackageManager().getPackageInstaller(); + installer.installExistingPackage(packageName, + PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, + PackageManager.INSTALL_REASON_UNKNOWN, sender, userId, null); + + try { + latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e(TAG, "Thread interrupted unexpectedly.", e); + } + } + + /** + * Launches the given package in the given user. + * Make sure the keyguard has been dismissed prior to calling. + */ + private void startApp(int userId, String packageName) throws RemoteException { + final Context context = InstrumentationRegistry.getContext(); + final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null, + context.getPackageName(), + context.getPackageManager().getLaunchIntentForPackage(packageName), null, null, + null, 0, 0, null, null, userId); + attestTrue("User " + userId + " failed to start " + packageName, + result.result == ActivityManager.START_SUCCESS); + } + private void registerUserSwitchObserver(final CountDownLatch switchLatch, final CountDownLatch bootCompleteLatch, final int userId) throws Exception { ActivityManager.getService().registerUserSwitchObserver( @@ -394,6 +710,44 @@ public class UserLifecycleTests { }, UserHandle.of(userId), new IntentFilter(action), null, null); } + private class ProgressWaiter extends IProgressListener.Stub { + private final CountDownLatch mFinishedLatch = new CountDownLatch(1); + + @Override + public void onStarted(int id, Bundle extras) {} + + @Override + public void onProgress(int id, int progress, Bundle extras) {} + + @Override + public void onFinished(int id, Bundle extras) { + mFinishedLatch.countDown(); + } + + public boolean waitForFinish(long timeoutSecs) { + try { + return mFinishedLatch.await(timeoutSecs, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e(TAG, "Thread interrupted unexpectedly.", e); + return false; + } + } + } + + /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */ + private int getUserTypePackageWhitelistMode() { + return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP, + USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); + } + + /** Sets the PACKAGE_WHITELIST_MODE_PROP System Property to the given value. */ + private void setUserTypePackageWhitelistMode(int mode) { + String result = ShellHelper.runShellCommand( + String.format("setprop %s %d", PACKAGE_WHITELIST_MODE_PROP, mode)); + attestFalse("Failed to set sysprop " + PACKAGE_WHITELIST_MODE_PROP + ": " + result, + result != null && result.contains("Failed")); + } + private void removeUser(int userId) { try { mUm.removeUser(userId); @@ -413,13 +767,13 @@ public class UserLifecycleTests { } } - private void attestTrue(String message, boolean attestion) { - if (!attestion) { + private void attestTrue(String message, boolean assertion) { + if (!assertion) { Log.w(TAG, message); } } - private void attestFalse(String message, boolean attestion) { - attestTrue(message, !attestion); + private void attestFalse(String message, boolean assertion) { + attestTrue(message, !assertion); } } diff --git a/apct-tests/perftests/textclassifier/run.sh b/apct-tests/perftests/textclassifier/run.sh index 8660d26388ac..d36d190a573a 100755 --- a/apct-tests/perftests/textclassifier/run.sh +++ b/apct-tests/perftests/textclassifier/run.sh @@ -1,5 +1,5 @@ set -e -make TextClassifierPerfTests perf-setup.sh +build/soong/soong_ui.bash --make-mode TextClassifierPerfTests perf-setup.sh adb install ${OUT}/testcases/TextClassifierPerfTests/arm64/TextClassifierPerfTests.apk adb shell cmd package compile -m speed -f com.android.perftests.textclassifier adb push ${OUT}/obj/EXECUTABLES/perf-setup.sh_intermediates/perf-setup.sh /data/local/tmp/ diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java index 40778de4e521..fe2b1f6443b3 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java @@ -16,12 +16,22 @@ package android.perftests.utils; +import android.annotation.IntDef; import android.app.Activity; import android.app.Instrumentation; import android.os.Bundle; +import android.util.ArrayMap; import android.util.Log; +import com.android.internal.util.ArrayUtils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -53,6 +63,47 @@ import java.util.concurrent.TimeUnit; public final class ManualBenchmarkState { private static final String TAG = ManualBenchmarkState.class.getSimpleName(); + @Target(ElementType.ANNOTATION_TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface StatsReport { + int FLAG_MEDIAN = 0x00000001; + int FLAG_MEAN = 0x00000002; + int FLAG_MIN = 0x00000004; + int FLAG_MAX = 0x00000008; + int FLAG_STDDEV = 0x00000010; + int FLAG_COEFFICIENT_VAR = 0x00000020; + int FLAG_ITERATION = 0x00000040; + + @Retention(RetentionPolicy.RUNTIME) + @IntDef(value = { + FLAG_MEDIAN, + FLAG_MEAN, + FLAG_MIN, + FLAG_MAX, + FLAG_STDDEV, + FLAG_COEFFICIENT_VAR, + FLAG_ITERATION, + }) + @interface Flag {} + + /** Defines which type of statistics should output. */ + @Flag int flags() default -1; + /** An array with value 0~100 to provide the percentiles. */ + int[] percentiles() default {}; + } + + /** The interface to receive the events of customized iteration. */ + public interface CustomizedIterationListener { + /** The customized iteration starts. */ + void onStart(int iteration); + + /** The customized iteration finished. */ + void onFinished(int iteration); + } + + /** It means the entire {@link StatsReport} is not given. */ + private static final int DEFAULT_STATS_REPORT = -2; + // TODO: Tune these values. // warm-up for duration private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5); @@ -67,24 +118,68 @@ public final class ManualBenchmarkState { private static final int NOT_STARTED = 0; // The benchmark has not started yet. private static final int WARMUP = 1; // The benchmark is warming up. private static final int RUNNING = 2; // The benchmark is running. - private static final int FINISHED = 3; // The benchmark has stopped. + private static final int RUNNING_CUSTOMIZED = 3; // Running for customized measurement. + private static final int FINISHED = 4; // The benchmark has stopped. private int mState = NOT_STARTED; // Current benchmark state. + private long mWarmupDurationNs = WARMUP_DURATION_NS; + private long mTargetTestDurationNs = TARGET_TEST_DURATION_NS; private long mWarmupStartTime = 0; private int mWarmupIterations = 0; private int mMaxIterations = 0; + /** + * Additinal iteration that used to apply customized measurement. The result during these + * iterations won't be counted into {@link #mStats}. + */ + private int mMaxCustomizedIterations; + private int mCustomizedIterations; + private CustomizedIterationListener mCustomizedIterationListener; + // Individual duration in nano seconds. private ArrayList<Long> mResults = new ArrayList<>(); + /** @see #addExtraResult(String, long) */ + private ArrayMap<String, ArrayList<Long>> mExtraResults; + + private final List<Long> mTmpDurations = Arrays.asList(0L); + // Statistics. These values will be filled when the benchmark has finished. // The computation needs double precision, but long int is fine for final reporting. private Stats mStats; + private int mStatsReportFlags = + StatsReport.FLAG_MEDIAN | StatsReport.FLAG_MEAN | StatsReport.FLAG_STDDEV; + private int[] mStatsReportPercentiles = {90 , 95}; + + private boolean shouldReport(int statsReportFlag) { + return (mStatsReportFlags & statsReportFlag) != 0; + } + + void configure(ManualBenchmarkTest testAnnotation) { + if (testAnnotation == null) { + return; + } + + final long warmupDurationNs = testAnnotation.warmupDurationNs(); + if (warmupDurationNs >= 0) { + mWarmupDurationNs = warmupDurationNs; + } + final long targetTestDurationNs = testAnnotation.targetTestDurationNs(); + if (targetTestDurationNs >= 0) { + mTargetTestDurationNs = targetTestDurationNs; + } + final StatsReport statsReport = testAnnotation.statsReport(); + if (statsReport != null && statsReport.flags() != DEFAULT_STATS_REPORT) { + mStatsReportFlags = statsReport.flags(); + mStatsReportPercentiles = statsReport.percentiles(); + } + } + private void beginBenchmark(long warmupDuration, int iterations) { - mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations)); + mMaxIterations = (int) (mTargetTestDurationNs / (warmupDuration / iterations)); mMaxIterations = Math.min(MAX_TEST_ITERATIONS, Math.max(mMaxIterations, MIN_TEST_ITERATIONS)); mState = RUNNING; @@ -99,29 +194,58 @@ public final class ManualBenchmarkState { if (duration < 0) { throw new RuntimeException("duration is negative: " + duration); } + mTmpDurations.set(0, duration); + return keepRunning(mTmpDurations); + } + + /** + * Similar to the {@link #keepRunning(long)} but accepts a list of durations + */ + public boolean keepRunning(List<Long> durations) { switch (mState) { case NOT_STARTED: mState = WARMUP; mWarmupStartTime = System.nanoTime(); return true; case WARMUP: { + if (ArrayUtils.isEmpty(durations)) { + return true; + } final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime; - ++mWarmupIterations; + mWarmupIterations += durations.size(); if (mWarmupIterations >= WARMUP_MIN_ITERATIONS - && timeSinceStartingWarmup >= WARMUP_DURATION_NS) { + && timeSinceStartingWarmup >= mWarmupDurationNs) { beginBenchmark(timeSinceStartingWarmup, mWarmupIterations); } return true; } case RUNNING: { - mResults.add(duration); + if (ArrayUtils.isEmpty(durations)) { + return true; + } + mResults.addAll(durations); final boolean keepRunning = mResults.size() < mMaxIterations; if (!keepRunning) { mStats = new Stats(mResults); + if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) { + mState = RUNNING_CUSTOMIZED; + mCustomizedIterationListener.onStart(mCustomizedIterations); + return true; + } mState = FINISHED; } return keepRunning; } + case RUNNING_CUSTOMIZED: { + mCustomizedIterationListener.onFinished(mCustomizedIterations); + mCustomizedIterations++; + if (mCustomizedIterations >= mMaxCustomizedIterations) { + mState = FINISHED; + return false; + } + mCustomizedIterationListener.onStart(mCustomizedIterations); + return true; + } case FINISHED: throw new IllegalStateException("The benchmark has finished."); default: @@ -129,31 +253,112 @@ public final class ManualBenchmarkState { } } - private String summaryLine() { - final StringBuilder sb = new StringBuilder(); - sb.append("Summary: "); - sb.append("median=").append(mStats.getMedian()).append("ns, "); - sb.append("mean=").append(mStats.getMean()).append("ns, "); - sb.append("min=").append(mStats.getMin()).append("ns, "); - sb.append("max=").append(mStats.getMax()).append("ns, "); - sb.append("sigma=").append(mStats.getStandardDeviation()).append(", "); - sb.append("iteration=").append(mResults.size()).append(", "); - sb.append("values=").append(mResults.toString()); + /** + * @return {@code true} if the benchmark is in warmup state. It can be used to skip the + * operations or measurements that are unnecessary while the test isn't running the + * actual benchmark. + */ + public boolean isWarmingUp() { + return mState == WARMUP; + } + + /** + * This is used to run the benchmark with more information by enabling some debug mechanism but + * we don't want to account the special runs (slower) in the stats report. + */ + public void setCustomizedIterations(int iterations, CustomizedIterationListener listener) { + mMaxCustomizedIterations = iterations; + mCustomizedIterationListener = listener; + } + + /** + * Adds additional result while this benchmark isn't warming up or running in customized state. + * It is used when a sequence of operations is executed consecutively, the duration of each + * operation can also be recorded. + */ + public void addExtraResult(String key, long duration) { + if (isWarmingUp() || mState == RUNNING_CUSTOMIZED) { + return; + } + if (mExtraResults == null) { + mExtraResults = new ArrayMap<>(); + } + mExtraResults.computeIfAbsent(key, k -> new ArrayList<>()).add(duration); + } + + private static String summaryLine(String key, Stats stats, ArrayList<Long> results) { + final StringBuilder sb = new StringBuilder(key); + sb.append(" Summary: "); + sb.append("median=").append(stats.getMedian()).append("ns, "); + sb.append("mean=").append(stats.getMean()).append("ns, "); + sb.append("min=").append(stats.getMin()).append("ns, "); + sb.append("max=").append(stats.getMax()).append("ns, "); + sb.append("sigma=").append(stats.getStandardDeviation()).append(", "); + sb.append("iteration=").append(results.size()).append(", "); + sb.append("values="); + if (results.size() > 100) { + sb.append(results.subList(0, 100)).append(" ..."); + } else { + sb.append(results); + } return sb.toString(); } + private void fillStatus(Bundle status, String key, Stats stats) { + if (shouldReport(StatsReport.FLAG_ITERATION)) { + status.putLong(key + "_iteration", stats.getSize()); + } + if (shouldReport(StatsReport.FLAG_MEDIAN)) { + status.putLong(key + "_median", stats.getMedian()); + } + if (shouldReport(StatsReport.FLAG_MEAN)) { + status.putLong(key + "_mean", Math.round(stats.getMean())); + } + if (shouldReport(StatsReport.FLAG_MIN)) { + status.putLong(key + "_min", stats.getMin()); + } + if (shouldReport(StatsReport.FLAG_MAX)) { + status.putLong(key + "_max", stats.getMax()); + } + if (mStatsReportPercentiles != null) { + for (int percentile : mStatsReportPercentiles) { + status.putLong(key + "_percentile" + percentile, stats.getPercentile(percentile)); + } + } + if (shouldReport(StatsReport.FLAG_STDDEV)) { + status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation())); + } + if (shouldReport(StatsReport.FLAG_COEFFICIENT_VAR)) { + status.putLong(key + "_cv", + Math.round((100 * stats.getStandardDeviation() / stats.getMean()))); + } + } + public void sendFullStatusReport(Instrumentation instrumentation, String key) { if (mState != FINISHED) { throw new IllegalStateException("The benchmark hasn't finished"); } - Log.i(TAG, key + summaryLine()); + Log.i(TAG, summaryLine(key, mStats, mResults)); final Bundle status = new Bundle(); - status.putLong(key + "_median", mStats.getMedian()); - status.putLong(key + "_mean", (long) mStats.getMean()); - status.putLong(key + "_percentile90", mStats.getPercentile90()); - status.putLong(key + "_percentile95", mStats.getPercentile95()); - status.putLong(key + "_stddev", (long) mStats.getStandardDeviation()); + fillStatus(status, key, mStats); + if (mExtraResults != null) { + for (int i = 0; i < mExtraResults.size(); i++) { + final String subKey = key + "_" + mExtraResults.keyAt(i); + final ArrayList<Long> results = mExtraResults.valueAt(i); + final Stats stats = new Stats(results); + Log.i(TAG, summaryLine(subKey, stats, results)); + fillStatus(status, subKey, stats); + } + } instrumentation.sendStatus(Activity.RESULT_OK, status); } -} + /** The annotation to customize the test, e.g. the duration of warm-up and target test. */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface ManualBenchmarkTest { + long warmupDurationNs() default -1; + long targetTestDurationNs() default -1; + StatsReport statsReport() default @StatsReport(flags = DEFAULT_STATS_REPORT); + } +} diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java index 8187c6fa63d5..8ff6a16e8b7e 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java @@ -16,7 +16,7 @@ package android.perftests.utils; -import androidx.test.InstrumentationRegistry; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -59,15 +59,15 @@ public class PerfManualStatusReporter implements TestRule { @Override public Statement apply(Statement base, Description description) { + mState.configure(description.getAnnotation(ManualBenchmarkState.ManualBenchmarkTest.class)); + return new Statement() { @Override public void evaluate() throws Throwable { base.evaluate(); - mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(), - description.getMethodName()); + mState.sendFullStatusReport(getInstrumentation(), description.getMethodName()); } }; } } - diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java index 8f03f7eea584..e934feb01a84 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java @@ -19,12 +19,28 @@ package android.perftests.utils; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.os.Bundle; +import android.view.WindowManager; + +/** + * A simple activity used for testing, e.g. performance of activity switching, or as a base + * container of testing view. + */ +public class PerfTestActivity extends Activity { + public static final String INTENT_EXTRA_KEEP_SCREEN_ON = "keep_screen_on"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getIntent().getBooleanExtra(INTENT_EXTRA_KEEP_SCREEN_ON, false)) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } -public class StubActivity extends Activity { public static Intent createLaunchIntent(Context context) { final Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClass(context, StubActivity.class); + intent.setClass(context, PerfTestActivity.class); return intent; } } diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java index 5e50073c0674..fb516a818f75 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/Stats.java @@ -16,23 +16,27 @@ package android.perftests.utils; +import android.annotation.IntRange; + import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Stats { - private long mMedian, mMin, mMax, mPercentile90, mPercentile95; + private long mMedian, mMin, mMax; private double mMean, mStandardDeviation; + private final List<Long> mValues; /* Calculate stats in constructor. */ public Stats(List<Long> values) { - // make a copy since we're modifying it - values = new ArrayList<>(values); final int size = values.size(); if (size < 2) { throw new IllegalArgumentException("At least two results are necessary."); } + // Make a copy since we're modifying it. + mValues = values = new ArrayList<>(values); + Collections.sort(values); mMin = values.get(0); @@ -40,8 +44,6 @@ public class Stats { mMedian = size % 2 == 0 ? (values.get(size / 2) + values.get(size / 2 - 1)) / 2 : values.get(size / 2); - mPercentile90 = getPercentile(values, 90); - mPercentile95 = getPercentile(values, 95); for (int i = 0; i < size; ++i) { long result = values.get(i); @@ -56,6 +58,10 @@ public class Stats { mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); } + public int getSize() { + return mValues.size(); + } + public double getMean() { return mMean; } @@ -76,12 +82,8 @@ public class Stats { return mStandardDeviation; } - public long getPercentile90() { - return mPercentile90; - } - - public long getPercentile95() { - return mPercentile95; + public long getPercentile(@IntRange(from = 0, to = 100) int percentile) { + return getPercentile(mValues, percentile); } private static long getPercentile(List<Long> values, int percentile) { diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java new file mode 100644 index 000000000000..a433d801acaf --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2019 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 android.perftests.utils; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.IntentSender; +import android.content.pm.PackageInstaller; +import android.content.res.Resources; +import android.util.Log; + +import org.junit.Assert; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Installs packages included within the assets directory. + */ +public class TestPackageInstaller { + private static final String LOG_TAG = "TestPackageInstaller"; + private static final String BROADCAST_ACTION = + "com.android.perftests.core.ACTION_INSTALL_COMMIT"; + + private final Context mContext; + public TestPackageInstaller(Context context) { + mContext = context; + } + + + + /** + * Installs an APK located at the specified path in the assets directory. + **/ + public InstalledPackage installPackage(String resourceName) throws IOException, + InterruptedException { + Log.d(LOG_TAG, "Installing resource APK '" + resourceName + "'"); + LocalBroadcastReceiver intentSender = new LocalBroadcastReceiver(mContext); + + // Initialize the package install session. + PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); + PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( + PackageInstaller.SessionParams.MODE_FULL_INSTALL); + params.setInstallAsInstantApp(false); + int sessionId = packageInstaller.createSession(params); + PackageInstaller.Session session = packageInstaller.openSession(sessionId); + + // Copy the apk to the install session. + try (OutputStream os = session.openWrite("TestPackageInstaller", 0, -1); + InputStream is = mContext.getResources().getAssets().openNonAsset(resourceName)) { + if (is == null) { + throw new IOException("Resource " + resourceName + " not found"); + } + byte[] buffer = new byte[4096]; + int n; + while ((n = is.read(buffer)) >= 0) { + os.write(buffer, 0, n); + } + } + + session.commit(intentSender.getIntentSender(sessionId)); + session.close(); + + // Retrieve the results of the installation. + Intent intent = intentSender.getIntentSenderResult(); + int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + Assert.assertEquals(PackageInstaller.STATUS_SUCCESS, status); + String packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME); + return new InstalledPackage(sessionId, packageName); + } + + public class InstalledPackage { + private int mSessionId; + private String mPackageName; + + private InstalledPackage(int sessionId, String packageName) { + mSessionId = sessionId; + mPackageName = packageName; + } + + public String getPackageName() { + return mPackageName; + } + + public void uninstall() throws Exception { + Log.d(LOG_TAG, "Uninstalling package '" + mPackageName + "'"); + LocalBroadcastReceiver intentSender = new LocalBroadcastReceiver(mContext); + PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller(); + packageInstaller.uninstall(mPackageName, intentSender.getIntentSender(mSessionId)); + int status = intentSender.getIntentSenderResult() + .getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); + Assert.assertEquals(PackageInstaller.STATUS_SUCCESS, status); + } + } + + private class LocalBroadcastReceiver extends BroadcastReceiver { + private final BlockingQueue<Intent> mIntentSenderResults = new LinkedBlockingQueue<>(); + private final Context mContext; + + private LocalBroadcastReceiver(Context context) { + mContext = context; + } + + @Override + public void onReceive(Context context, Intent intent) { + mIntentSenderResults.add(intent); + } + + IntentSender getIntentSender(int sessionId) { + String action = BROADCAST_ACTION + "." + sessionId; + IntentFilter filter = new IntentFilter(action); + mContext.registerReceiver(this, filter); + + Intent intent = new Intent(action); + PendingIntent pending = PendingIntent.getBroadcast(mContext, sessionId, intent, + PendingIntent.FLAG_UPDATE_CURRENT); + return pending.getIntentSender(); + } + + Intent getIntentSenderResult() throws InterruptedException { + return mIntentSenderResults.take(); + } + } +} diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java new file mode 100644 index 000000000000..b15b6f61ae5d --- /dev/null +++ b/apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2019 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 android.perftests.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +/** + * Utility to get the slice of tracing_mark_write S,F,B,E (Async: start, finish, Sync: begin, end). + * Use {@link #visit(String)} to process the trace in text form. The filtered results can be + * obtained by {@link #forAllSlices(BiConsumer)}. + * + * @see android.os.Trace + */ +public class TraceMarkParser { + /** All slices by the name of {@link TraceMarkLine}. */ + private final Map<String, List<TraceMarkSlice>> mSlicesMap = new HashMap<>(); + /** The nested depth of each task-pid. */ + private final Map<String, Integer> mDepthMap = new HashMap<>(); + /** The start trace lines that haven't matched the corresponding end. */ + private final Map<String, TraceMarkLine> mPendingStarts = new HashMap<>(); + + private final Predicate<TraceMarkLine> mTraceLineFilter; + + private static final long MICROS_PER_SECOND = 1000L * 1000L; + + public TraceMarkParser(Predicate<TraceMarkLine> traceLineFilter) { + mTraceLineFilter = traceLineFilter; + } + + /** Only accept the trace event with the given names. */ + public TraceMarkParser(String... traceNames) { + this(line -> { + for (String name : traceNames) { + if (name.equals(line.name)) { + return true; + } + } + return false; + }); + } + + /** Computes {@link TraceMarkSlice} by the given trace line. */ + public void visit(String textTraceLine) { + final TraceMarkLine line = TraceMarkLine.parse(textTraceLine); + if (line == null) { + return; + } + + if (line.isAsync) { + // Async-trace contains name in the start and finish event. + if (mTraceLineFilter.test(line)) { + if (line.isBegin) { + mPendingStarts.put(line.name, line); + } else { + final TraceMarkLine start = mPendingStarts.remove(line.name); + if (start != null) { + addSlice(start, line); + } + } + } + return; + } + + int depth = 1; + if (line.isBegin) { + final Integer existingDepth = mDepthMap.putIfAbsent(line.taskPid, 1); + if (existingDepth != null) { + mDepthMap.put(line.taskPid, depth = existingDepth + 1); + } + // Sync-trace only contains name in the begin event. + if (mTraceLineFilter.test(line)) { + mPendingStarts.put(getSyncPendingStartKey(line, depth), line); + } + } else { + final Integer existingDepth = mDepthMap.get(line.taskPid); + if (existingDepth != null) { + depth = existingDepth; + mDepthMap.put(line.taskPid, existingDepth - 1); + } + final TraceMarkLine begin = mPendingStarts.remove(getSyncPendingStartKey(line, depth)); + if (begin != null) { + addSlice(begin, line); + } + } + } + + private static String getSyncPendingStartKey(TraceMarkLine line, int depth) { + return line.taskPid + "@" + depth; + } + + private void addSlice(TraceMarkLine begin, TraceMarkLine end) { + mSlicesMap.computeIfAbsent( + begin.name, k -> new ArrayList<>()).add(new TraceMarkSlice(begin, end)); + } + + public void forAllSlices(BiConsumer<String, List<TraceMarkSlice>> consumer) { + for (Map.Entry<String, List<TraceMarkSlice>> entry : mSlicesMap.entrySet()) { + consumer.accept(entry.getKey(), entry.getValue()); + } + } + + public void reset() { + mSlicesMap.clear(); + mDepthMap.clear(); + mPendingStarts.clear(); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + forAllSlices((key, slices) -> { + double totalMs = 0; + for (TraceMarkSlice s : slices) { + totalMs += s.getDurationInSeconds() * 1000; + } + sb.append(key).append(" count=").append(slices.size()).append(" avg=") + .append(totalMs / slices.size()).append("ms\n"); + }); + + if (!mPendingStarts.isEmpty()) { + sb.append("[Warning] Unresolved events:").append(mPendingStarts).append("\n"); + } + return sb.toString(); + } + + static double microsecondToSeconds(long ms) { + return (ms * 1.0d) / MICROS_PER_SECOND; + } + + public static class TraceMarkSlice { + public final TraceMarkLine begin; + public final TraceMarkLine end; + + TraceMarkSlice(TraceMarkLine begin, TraceMarkLine end) { + this.begin = begin; + this.end = end; + } + + public double getDurationInSeconds() { + return microsecondToSeconds(end.timestamp - begin.timestamp); + } + + public long getDurationInMicroseconds() { + return end.timestamp - begin.timestamp; + } + } + + // taskPid timestamp name + // # Async: + // Binder:129_F-349 ( 1296) [003] ...1 12.2776: tracing_mark_write: S|1296|launching: a.test|0 + // android.anim-135 ( 1296) [005] ...1 12.3361: tracing_mark_write: F|1296|launching: a.test|0 + // # Normal: + // Binder:129_6-315 ( 1296) [007] ...1 97.4576: tracing_mark_write: B|1296|relayoutWindow: xxx + // ... there may have other nested begin/end + // Binder:129_6-315 ( 1296) [007] ...1 97.4580: tracing_mark_write: E|1296 + public static class TraceMarkLine { + static final String EVENT_KEYWORD = ": tracing_mark_write: "; + static final char ASYNC_START = 'S'; + static final char ASYNC_FINISH = 'F'; + static final char SYNC_BEGIN = 'B'; + static final char SYNC_END = 'E'; + + public final String taskPid; + public final long timestamp; // in microseconds + public final String name; + public final boolean isAsync; + public final boolean isBegin; + + TraceMarkLine(String rawLine, int typePos, int type) throws IllegalArgumentException { + taskPid = rawLine.substring(0, rawLine.indexOf('(')).trim(); + final int timeEnd = rawLine.indexOf(':', taskPid.length()); + if (timeEnd < 0) { + throw new IllegalArgumentException("Timestamp end not found"); + } + final int timeBegin = rawLine.lastIndexOf(' ', timeEnd); + if (timeBegin < 0) { + throw new IllegalArgumentException("Timestamp start not found"); + } + timestamp = parseMicroseconds(rawLine.substring(timeBegin, timeEnd)); + isAsync = type == ASYNC_START || type == ASYNC_FINISH; + isBegin = type == ASYNC_START || type == SYNC_BEGIN; + + if (!isAsync && !isBegin) { + name = ""; + } else { + // Get the position of the second '|' from "S|1234|name". + final int nameBegin = rawLine.indexOf('|', typePos + 2) + 1; + if (nameBegin == 0) { + throw new IllegalArgumentException("Name begin not found"); + } + if (isAsync) { + // Get the name from "S|1234|name|0". + name = rawLine.substring(nameBegin, rawLine.lastIndexOf('|')); + } else { + name = rawLine.substring(nameBegin); + } + } + } + + static TraceMarkLine parse(String rawLine) { + final int eventPos = rawLine.indexOf(EVENT_KEYWORD); + if (eventPos < 0) { + return null; + } + final int typePos = eventPos + EVENT_KEYWORD.length(); + if (typePos >= rawLine.length()) { + return null; + } + final int type = rawLine.charAt(typePos); + if (type != ASYNC_START && type != ASYNC_FINISH + && type != SYNC_BEGIN && type != SYNC_END) { + return null; + } + + try { + return new TraceMarkLine(rawLine, typePos, type); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Parse the timestamp from atrace output, the format will be like: + * 84962.920719 where the decimal part will be always exactly 6 digits. + * ^^^^^ ^^^^^^ + * | | + * sec microsec + */ + static long parseMicroseconds(String line) { + int end = line.length(); + long t = 0; + for (int i = 0; i < end; i++) { + char c = line.charAt(i); + if (c >= '0' && c <= '9') { + t = t * 10 + (c - '0'); + } + } + return t; + } + + @Override + public String toString() { + return "TraceMarkLine{pid=" + taskPid + " time=" + + microsecondToSeconds(timestamp) + " name=" + name + + " async=" + isAsync + " begin=" + isBegin + "}"; + } + } +} |