summaryrefslogtreecommitdiff
path: root/apct-tests
diff options
context:
space:
mode:
Diffstat (limited to 'apct-tests')
-rw-r--r--apct-tests/perftests/autofill/AndroidManifest.xml2
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java12
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java4
-rw-r--r--apct-tests/perftests/core/Android.mk6
-rw-r--r--apct-tests/perftests/core/AndroidManifest.xml9
-rw-r--r--apct-tests/perftests/core/AndroidTest.xml5
-rw-r--r--apct-tests/perftests/core/apps/overlay/Android.bp188
-rw-r--r--apct-tests/perftests/core/apps/overlay/AndroidManifest.xml21
-rw-r--r--apct-tests/perftests/core/apps/overlay/res/values/values.xml19
-rw-r--r--apct-tests/perftests/core/apps/overlay/res_large/values/values.xml274
-rw-r--r--apct-tests/perftests/core/apps/reources_manager/Android.bp34
-rw-r--r--apct-tests/perftests/core/apps/reources_manager/AndroidManifest.xml20
-rw-r--r--apct-tests/perftests/core/res/color/color_state_list.xml25
-rw-r--r--apct-tests/perftests/core/res/values/overlayable.xml280
-rw-r--r--apct-tests/perftests/core/res/values/strings.xml32
-rw-r--r--apct-tests/perftests/core/res/values/values.xml368
-rw-r--r--apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java234
-rw-r--r--apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java4
-rw-r--r--apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java139
-rw-r--r--apct-tests/perftests/core/src/android/app/ResourcesPerfTest.java165
-rw-r--r--apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java71
-rw-r--r--apct-tests/perftests/core/src/android/graphics/perftests/PaintHasGlyphPerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/graphics/perftests/VectorDrawablePerfTest.java6
-rw-r--r--apct-tests/perftests/core/src/android/os/PackageManagerPerfTest.java3
-rw-r--r--apct-tests/perftests/core/src/android/text/DynamicLayoutPerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/widget/EditTextBackspacePerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/widget/EditTextCursorMovementPerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/widget/LayoutPerfTest.java6
-rw-r--r--apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java6
-rw-r--r--apct-tests/perftests/core/src/android/widget/TextViewSetTextLocalePerfTest.java5
-rw-r--r--apct-tests/perftests/core/src/android/wm/InternalWindowOperationPerfTest.java121
-rw-r--r--apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java211
-rw-r--r--apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java157
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java126
-rw-r--r--apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java184
-rw-r--r--apct-tests/perftests/multiuser/AndroidManifest.xml3
-rw-r--r--apct-tests/perftests/multiuser/AndroidTest.xml1
-rw-r--r--apct-tests/perftests/multiuser/apps/dummyapp/Android.bp21
-rw-r--r--apct-tests/perftests/multiuser/apps/dummyapp/AndroidManifest.xml35
-rw-r--r--apct-tests/perftests/multiuser/apps/dummyapp/src/com/android/multiuser/test/DummyForegroundActivity.java51
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java498
-rwxr-xr-xapct-tests/perftests/textclassifier/run.sh2
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java249
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/PerfManualStatusReporter.java8
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java (renamed from apct-tests/perftests/utils/src/android/perftests/utils/StubActivity.java)20
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/Stats.java24
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java145
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/TraceMarkParser.java268
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 + "}";
+ }
+ }
+}