[automerger skipped] Merge "DO NOT MERGE Add an OEM configurable limit for zen rules" into qt-dev am: 81f051eff4 am: 14dec12d60 -s ours am: 112d4908aa -s ours am: 9b1a9dc79f -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17045726

Change-Id: Ib9be9ab77f7a88b0e679383e04fee65ecdaad581
diff --git a/.gitignore b/.gitignore
index c47cc8b..5018436 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 .idea
 *.iml
 *.sw*
-gen/
\ No newline at end of file
+gen/
+.vscode/
+*.code-workspace
diff --git a/.prebuilt_info/OWNERS b/.prebuilt_info/OWNERS
new file mode 100644
index 0000000..eb8b89b
--- /dev/null
+++ b/.prebuilt_info/OWNERS
@@ -0,0 +1 @@
+per-file prebuilt_info_packages_CtsShim_*.asciipb = file:/packages/CtsShim/OWNERS
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 29bcfe0..0ccd951 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "6508977"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPriv.apk"
   }
@@ -8,5 +8,8 @@
   version: ""
   version_group: ""
   git_project: "platform/frameworks/base"
-  git_branch: "rvc-dev"
+  git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index be172e6..7e85c8f 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "6508977"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShim.apk"
   }
@@ -8,5 +8,8 @@
   version: ""
   version_group: ""
   git_project: "platform/frameworks/base"
-  git_branch: "rvc-dev"
+  git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 13eca13..20c2785 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "6508977"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPriv.apk"
   }
@@ -8,5 +8,8 @@
   version: ""
   version_group: ""
   git_project: "platform/frameworks/base"
-  git_branch: "rvc-dev"
+  git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 2e863fe..13e3ae5 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "6508977"
+    build_id: "7552332"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShim.apk"
   }
@@ -8,5 +8,8 @@
   version: ""
   version_group: ""
   git_project: "platform/frameworks/base"
-  git_branch: "rvc-dev"
+  git_branch: "sc-dev"
+  transform: TRANSFORM_NONE
+  transform_options {
+  }
 }
diff --git a/Android.bp b/Android.bp
index 95e3041..3f7581c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,205 +25,53 @@
 //
 // READ ME: ########################################################
 
-filegroup {
-    name: "framework-core-sources",
-    srcs: [
-        "core/java/**/*.java",
-        "core/java/**/*.aidl",
-    ],
-    path: "core/java",
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
 }
 
-// These are subset of framework-core-sources that are needed by the
-// android.test.mock library. Ideally, the library should use public APIs only,
-// but unfortunately its API signature has some references to these private APIs.
-filegroup {
-    name: "framework-core-sources-for-test-mock",
-    srcs: [
-        "core/java/android/app/IApplicationThread.aidl",
-        "core/java/android/app/IServiceConnection.aidl",
-        "core/java/android/content/IContentProvider.java",
-        "core/java/android/content/pm/IPackageDataObserver.aidl",
-        "core/java/android/content/pm/InstantAppInfo.java",
-        "core/java/android/content/pm/KeySet.java",
-        "core/java/android/content/pm/PackageManager.java",
-        "core/java/android/content/pm/VerifierDeviceIdentity.java",
-        "core/java/android/content/res/Resources.java",
-        "core/java/android/os/storage/VolumeInfo.java",
-        "core/java/android/view/DisplayAdjustments.java",
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_base_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-CC-BY",
+        "SPDX-license-identifier-CPL-1.0",
+        "SPDX-license-identifier-GPL",
+        "SPDX-license-identifier-GPL-2.0",
+        "SPDX-license-identifier-MIT",
+        "SPDX-license-identifier-Unicode-DFS",
+        "SPDX-license-identifier-W3C",
+        "legacy_unencumbered",
     ],
-    path: "core/java",
-    visibility: ["//frameworks/base/test-mock"],
-}
-
-filegroup {
-    name: "framework-drm-sources",
-    srcs: [
-        "drm/java/**/*.java",
+    license_text: [
+        "NOTICE",
     ],
-    path: "drm/java",
-}
-
-filegroup {
-    name: "framework-graphics-sources",
-    srcs: [
-        "graphics/java/**/*.java",
-        "graphics/java/**/*.aidl",
-    ],
-    path: "graphics/java",
-}
-
-filegroup {
-    name: "framework-identity-sources",
-    srcs: [
-        "identity/java/**/*.java",
-    ],
-    path: "identity/java",
-}
-
-filegroup {
-    name: "framework-keystore-sources",
-    srcs: [
-        "keystore/java/**/*.java",
-        "keystore/java/**/*.aidl",
-    ],
-    path: "keystore/java",
-}
-
-filegroup {
-    name: "framework-location-sources",
-    srcs: [
-        "location/java/**/*.java",
-        "location/java/**/*.aidl",
-    ],
-    path: "location/java",
-}
-
-filegroup {
-    name: "framework-lowpan-sources",
-    srcs: [
-        "lowpan/java/**/*.java",
-        "lowpan/java/**/*.aidl",
-    ],
-    path: "lowpan/java",
-}
-
-filegroup {
-    name: "framework-media-sources",
-    srcs: [
-        "media/java/**/*.java",
-        "media/java/**/*.aidl",
-    ],
-    path: "media/java",
-}
-
-filegroup {
-    name: "framework-mca-effect-sources",
-    srcs: [
-        "media/mca/effect/java/**/*.java",
-    ],
-    path: "media/mca/effect/java",
-}
-
-filegroup {
-    name: "framework-mca-filterfw-sources",
-    srcs: [
-        "media/mca/filterfw/java/**/*.java",
-    ],
-    path: "media/mca/filterfw/java",
-}
-
-filegroup {
-    name: "framework-mca-filterpacks-sources",
-    srcs: [
-        "media/mca/filterpacks/java/**/*.java",
-    ],
-    path: "media/mca/filterpacks/java",
-}
-
-filegroup {
-    name: "framework-mime-sources",
-    srcs: [
-        "mime/java/**/*.java",
-    ],
-    path: "mime/java",
-}
-
-filegroup {
-    name: "framework-opengl-sources",
-    srcs: [
-        "opengl/java/**/*.java",
-    ],
-    path: "opengl/java",
-}
-
-filegroup {
-    name: "framework-rs-sources",
-    srcs: [
-        "rs/java/**/*.java",
-    ],
-    path: "rs/java",
-}
-
-filegroup {
-    name: "framework-sax-sources",
-    srcs: [
-        "sax/java/**/*.java",
-    ],
-    path: "sax/java",
-}
-
-filegroup {
-    name: "framework-telecomm-sources",
-    srcs: [
-        "telecomm/java/**/*.java",
-        "telecomm/java/**/*.aidl",
-    ],
-    path: "telecomm/java",
-}
-
-filegroup {
-    name: "framework-telephony-sources",
-    srcs: [
-        "telephony/java/**/*.java",
-        "telephony/java/**/*.aidl",
-    ],
-    path: "telephony/java",
-}
-
-genrule {
-    name: "statslog-telephony-common-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common"
-        + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
-    out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
-}
-
-filegroup {
-    name: "framework-telephony-common-sources",
-    srcs: [
-        "telephony/common/**/*.java",
-        ":statslog-telephony-common-java-gen",
-    ],
-}
-
-filegroup {
-    name: "framework-mms-sources",
-    srcs: [
-        "mms/java/**/*.java",
-        "mms/java/**/*.aidl",
-    ],
-    path: "mms/java",
 }
 
 filegroup {
     name: "framework-non-updatable-sources",
     srcs: [
         // Java/AIDL sources under frameworks/base
+        ":framework-annotations",
         ":framework-blobstore-sources",
         ":framework-core-sources",
         ":framework-drm-sources",
-        ":framework-graphics-sources",
+        ":framework-graphics-nonupdatable-sources",
         ":framework-jobscheduler-sources", // jobscheduler is not a module for R
         ":framework-keystore-sources",
         ":framework-identity-sources",
@@ -240,6 +88,7 @@
         ":framework-telecomm-sources",
         ":framework-telephony-common-sources",
         ":framework-telephony-sources",
+        ":framework-vcn-util-sources",
         ":framework-wifi-annotations",
         ":framework-wifi-non-updatable-sources",
         ":PacProcessor-aidl-sources",
@@ -250,24 +99,36 @@
         ":platform-compat-native-aidl",
 
         // AIDL sources from external directories
+        ":android.hardware.security.keymint-V1-java-source",
+        ":android.hardware.security.secureclock-V1-java-source",
+        ":android.security.apc-java-source",
+        ":android.security.authorization-java-source",
+        ":android.security.legacykeystore-java-source",
+        ":android.security.maintenance-java-source",
+        ":android.security.metrics-java-source",
+        ":android.system.keystore2-V1-java-source",
         ":credstore_aidl",
         ":dumpstate_aidl",
         ":framework_native_aidl",
         ":gatekeeper_aidl",
         ":gsiservice_aidl",
+        ":idmap2_aidl",
         ":guiconstants_aidl",
+        ":idmap2_core_aidl",
         ":incidentcompanion_aidl",
+        ":inputconstants_aidl",
         ":installd_aidl",
-        ":keystore_aidl",
         ":libaudioclient_aidl",
         ":libbinder_aidl",
         ":libbluetooth-binder-aidl",
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
+        ":packagemanager_aidl",
         ":libupdate_engine_aidl",
         ":resourcemanager_aidl",
         ":storaged_aidl",
         ":vold_aidl",
+        ":deviceproductinfoconstants_aidl",
 
         // For the generated R.java and Manifest.java
         ":framework-res{.aapt.srcjar}",
@@ -275,43 +136,56 @@
         // etc.
         ":framework-javastream-protos",
         ":statslog-framework-java-gen", // FrameworkStatsLog.java
+        ":audio_policy_configuration_V7_0",
     ],
 }
 
-filegroup {
-    name: "framework-updatable-sources",
-    srcs: [
-        ":framework-mediaprovider-sources",
-        ":framework-permission-sources",
-        ":framework-sdkextensions-sources",
-        ":framework-statsd-sources",
-        ":framework-tethering-srcs",
-        ":framework-wifi-updatable-sources",
-        ":updatable-media-srcs",
-    ]
-}
-
 java_library {
     name: "framework-updatable-stubs-module_libs_api",
     static_libs: [
+        "android.net.ipsec.ike.stubs.module_lib",
+        "framework-appsearch.stubs.module_lib",
+        "framework-connectivity.stubs.module_lib",
+        "framework-graphics.stubs.module_lib",
         "framework-media.stubs.module_lib",
         "framework-mediaprovider.stubs.module_lib",
         "framework-permission.stubs.module_lib",
+        "framework-permission-s.stubs.module_lib",
+        "framework-scheduling.stubs.module_lib",
         "framework-sdkextensions.stubs.module_lib",
         "framework-statsd.stubs.module_lib",
         "framework-tethering.stubs.module_lib",
         "framework-wifi.stubs.module_lib",
     ],
     sdk_version: "module_current",
-    visibility: [":__pkg__"],
+    visibility: ["//visibility:private"],
 }
 
-filegroup {
-    name: "framework-all-sources",
-    srcs: [
-        ":framework-mime-sources",
-        ":framework-non-updatable-sources",
-        ":framework-updatable-sources",
+java_library {
+    name: "framework-all",
+    installable: false,
+    static_libs: [
+        "android.net.ipsec.ike.impl",
+        "framework-minus-apex",
+        "framework-appsearch.impl",
+        "framework-connectivity.impl",
+        "framework-graphics.impl",
+        "framework-mediaprovider.impl",
+        "framework-permission.impl",
+        "framework-permission-s.impl",
+        "framework-scheduling.impl",
+        "framework-sdkextensions.impl",
+        "framework-statsd.impl",
+        "framework-tethering.impl",
+        "framework-wifi.impl",
+        "updatable-media",
+    ],
+    apex_available: ["//apex_available:platform"],
+    sdk_version: "core_platform",
+    visibility: [
+        // DO NOT ADD ANY MORE ENTRIES TO THIS LIST
+        "//external/robolectric-shadows:__subpackages__",
+        "//frameworks/layoutlib:__subpackages__",
     ],
 }
 
@@ -351,15 +225,16 @@
     name: "framework-internal-utils",
     static_libs: [
         "apex_aidl_interface-java",
-        "suspend_control_aidl_interface-java",
         "framework-protos",
-        "game-driver-protos",
+        "updatable-driver-protos",
+        "ota_metadata_proto_java",
         "android.hidl.base-V1.0-java",
         "android.hardware.cas-V1.0-java",
         "android.hardware.cas-V1.1-java",
         "android.hardware.cas-V1.2-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.contexthub-V1.1-java",
+        "android.hardware.contexthub-V1.2-java",
         "android.hardware.gnss-V1.0-java",
         "android.hardware.gnss-V2.1-java",
         "android.hardware.health-V1.0-java-constants",
@@ -369,140 +244,135 @@
         "android.hardware.radio-V1.3-java",
         "android.hardware.radio-V1.4-java",
         "android.hardware.radio-V1.5-java",
+        "android.hardware.radio-V1.6-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
         "android.hardware.tv.tuner-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.1-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
         "android.hardware.usb.gadget-V1.0-java",
+        "android.hardware.usb.gadget-V1.1-java",
+        "android.hardware.usb.gadget-V1.2-java",
         "android.hardware.vibrator-V1.0-java",
         "android.hardware.vibrator-V1.1-java",
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
+        "android.hardware.vibrator-V2-java",
+        "android.system.suspend.control.internal-java",
         "devicepolicyprotosnano",
 
         "com.android.sysprop.apex",
         "com.android.sysprop.init",
+        "com.android.sysprop.localization",
         "PlatformProperties",
     ],
     sdk_version: "core_platform",
     installable: false,
 }
 
-java_defaults {
-    name: "framework-defaults",
-    defaults: ["framework-aidl-export-defaults"],
-    installable: true,
+// NOTE: This filegroup is exposed for vendor libraries to depend on and is referenced in
+// documentation. Do not remove without consulting the treble/hidl teams.
+filegroup {
+    name: "framework-jarjar-rules",
+    srcs: ["framework-jarjar-rules.txt"],
+    visibility: ["//visibility:public"],
+}
 
+java_defaults {
+    name: "framework-minus-apex-defaults",
+    defaults: ["framework-aidl-export-defaults"],
+    srcs: [
+        ":framework-non-updatable-sources",
+        "core/java/**/*.logtags",
+    ],
     aidl: {
         generate_get_transaction_name: true,
+        local_include_dirs: [
+            "media/aidl",
+        ],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+            "packages/modules/Connectivity/framework/aidl-export",
+        ],
     },
-
-    srcs: ["core/java/**/*.logtags"],
-
-    exclude_srcs: [
-        // See comment on framework-atb-backward-compatibility module below
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
-    ],
-
-    sdk_version: "core_platform",
-    libs: [
-        "app-compat-annotations",
-        "ext",
-        "unsupportedappusage",
-    ],
-
-    jarjar_rules: ":framework-jarjar-rules",
-
-    static_libs: [
-        "framework-internal-utils",
-    ],
-
     dxflags: [
         "--core-library",
         "--multi-dex",
     ],
-
+    jarjar_rules: ":framework-jarjar-rules",
+    javac_shard_size: 150,
     plugins: [
         "view-inspector-annotation-processor",
         "staledataclass-annotation-processor",
+        "error_prone_android_framework",
     ],
-
     required: [
+        "framework-platform-compat-config",
         // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
         "gps_debug.conf",
+        "icu4j-platform-compat-config",
         "protolog.conf.json.gz",
+        "services-platform-compat-config",
+        "documents-ui-compat-config",
+        "calendar-provider-compat-config",
     ],
-}
-
-filegroup {
-    name: "framework-jarjar-rules",
-    srcs: ["framework-jarjar-rules.txt"],
-}
-
-filegroup {
-    name: "libincident_aidl",
-    srcs: [
-        "core/java/android/os/IIncidentDumpCallback.aidl",
-        "core/java/android/os/IIncidentManager.aidl",
-        "core/java/android/os/IIncidentReportStatusListener.aidl",
+    libs: [
+        "app-compat-annotations",
+        "ext",
+        "framework-updatable-stubs-module_libs_api",
+        "unsupportedappusage",
     ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "libvibrator_aidl",
-    srcs: [
-        "core/java/android/os/IExternalVibrationController.aidl",
-        "core/java/android/os/IExternalVibratorService.aidl",
+    sdk_version: "core_platform",
+    static_libs: [
+        "bouncycastle-repackaged-unbundled",
+        "framework-internal-utils",
+        // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
+        // in favor of an API stubs dependency in java_library "framework" below.
+        "mimemap",
+        "av-types-aidl-java",
+        "tv_tuner_resource_manager_aidl_interface-java",
+        "soundtrigger_middleware-aidl-java",
+        "modules-utils-preconditions",
+        "modules-utils-os",
+        "framework-permission-aidl-java",
     ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "libpowermanager_aidl",
-    srcs: [
-        "core/java/android/os/Temperature.aidl",
-        "core/java/android/os/CoolingDevice.aidl",
-        "core/java/android/os/IThermalEventListener.aidl",
-        "core/java/android/os/IThermalStatusListener.aidl",
-        "core/java/android/os/IThermalService.aidl",
-    ],
-    path: "core/java",
 }
 
 java_library {
     name: "framework-minus-apex",
-    defaults: ["framework-defaults"],
-    srcs: [":framework-non-updatable-sources"],
+    defaults: ["framework-minus-apex-defaults"],
     installable: true,
-    javac_shard_size: 150,
-    required: [
-        "framework-platform-compat-config",
-        "libcore-platform-compat-config",
-        "services-platform-compat-config",
-        "documents-ui-compat-config",
-    ],
-    libs: ["framework-updatable-stubs-module_libs_api"],
-    static_libs: [
-        // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
-        // in favor of an API stubs dependency in java_library "framework" below.
-        "mimemap",
-    ],
     // For backwards compatibility.
     stem: "framework",
     apex_available: ["//apex_available:platform"],
     visibility: [
         "//frameworks/base",
         // TODO(b/147128803) remove the below lines
+        "//frameworks/base/apex/appsearch/framework",
         "//frameworks/base/apex/blobstore/framework",
         "//frameworks/base/apex/jobscheduler/framework",
         "//frameworks/base/packages/Tethering/tests/unit",
+        "//packages/modules/Connectivity/Tethering/tests/unit",
     ],
+    errorprone: {
+        javacflags: [
+            "-Xep:AndroidFrameworkBinderIdentity:ERROR",
+            "-Xep:AndroidFrameworkCompatChange:ERROR",
+            "-Xep:AndroidFrameworkUid:ERROR",
+        ],
+    },
+}
+
+java_library {
+    name: "framework-minus-apex-intdefs",
+    defaults: ["framework-minus-apex-defaults"],
+    plugins: ["intdef-annotation-processor"],
 }
 
 // This "framework" module is NOT installed to the device. It's
@@ -521,167 +391,28 @@
     static_libs: [
         "app-compat-annotations",
         "framework-minus-apex",
+        "framework-appsearch.impl", // TODO(b/146218515): should be removed
         "framework-updatable-stubs-module_libs_api",
     ],
     sdk_version: "core_platform",
     apex_available: ["//apex_available:platform"],
 }
 
-java_library {
-    name: "framework-all",
-    defaults: ["framework-defaults"],
-    srcs: [":framework-all-sources"],
-    installable: false,
-    static_libs: [
-        "exoplayer2-extractor",
-        "android.hardware.wifi-V1.0-java-constants",
-        // Additional dependencies needed to build the ike API classes.
-        "ike-internals",
-    ],
-    apex_available: ["//apex_available:platform"],
-    visibility: [
-        // DO NOT ADD ANY MORE ENTRIES TO THIS LIST
-        "//external/robolectric-shadows:__subpackages__",
-        "//frameworks/base",
-        "//frameworks/layoutlib:__subpackages__",
-    ],
-}
-
 platform_compat_config {
     name: "framework-platform-compat-config",
     src: ":framework-minus-apex",
 }
 
-// A temporary build target that is conditionally included on the bootclasspath if
-// android.test.base library has been removed and which provides support for
-// maintaining backwards compatibility for APKs that target pre-P and depend on
-// android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
-// specified on the build command line.
-java_library {
-    name: "framework-atb-backward-compatibility",
-    installable: true,
-    libs: ["app-compat-annotations"],
-    srcs: [
-        "core/java/android/content/pm/AndroidTestBaseUpdater.java",
-    ],
-}
-
-genrule {
-    name: "statslog-framework-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
-         " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
-    out: ["com/android/internal/util/FrameworkStatsLog.java"],
-}
-
-java_library {
-    name: "uieventloggerlib",
-    srcs: [
-        "core/java/com/android/internal/logging/UiEvent.java",
-        "core/java/com/android/internal/logging/UiEventLogger.java",
-        "core/java/com/android/internal/logging/UiEventLoggerImpl.java",
-        "core/java/com/android/internal/logging/InstanceId.java",
-        "core/java/com/android/internal/logging/InstanceIdSequence.java",
-        ":statslog-framework-java-gen",
-    ],
-}
-
-gensrcs {
-    name: "framework-javastream-protos",
-    depfile: true,
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-javastream",
-        "soong_zip",
-    ],
-
-    cmd: "mkdir -p $(genDir)/$(in) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-javastream) " +
-        "  --dependency_out=$(depfile) " +
-        "  --javastream_out=$(genDir)/$(in) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in) " +
-        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "core/proto/**/*.proto",
-        "libs/incident/**/*.proto",
-    ],
-    output_extension: "srcjar",
-}
-
-gensrcs {
-    name: "framework-cppstream-protos",
-    depfile: true,
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-cppstream",
-    ],
-
-    cmd: "mkdir -p $(genDir) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-cppstream) " +
-        "  --dependency_out=$(depfile) " +
-        "  --cppstream_out=$(genDir) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in)",
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "core/proto/**/*.proto",
-        "libs/incident/**/*.proto",
-    ],
-
-    output_extension: "proto.h",
-}
-
-filegroup {
-    name: "framework-annotations",
-    srcs: [
-        "core/java/android/annotation/CallbackExecutor.java",
-        "core/java/android/annotation/CheckResult.java",
-        "core/java/android/annotation/CurrentTimeMillisLong.java",
-        "core/java/android/annotation/Hide.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/LongDef.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/RequiresPermission.java",
-        "core/java/android/annotation/SdkConstant.java",
-        "core/java/android/annotation/StringDef.java",
-        "core/java/android/annotation/SystemApi.java",
-        "core/java/android/annotation/SystemService.java",
-        "core/java/android/annotation/TestApi.java",
-        "core/java/android/annotation/WorkerThread.java",
-        "core/java/com/android/internal/annotations/GuardedBy.java",
-        "core/java/com/android/internal/annotations/VisibleForTesting.java",
-        "core/java/com/android/internal/annotations/Immutable.java",
-    ],
-}
-
-java_library {
-    name: "framework-annotations-lib",
-    srcs: [ ":framework-annotations" ],
-    sdk_version: "core_current",
-}
-
 filegroup {
     name: "framework-ike-shared-srcs",
     visibility: ["//packages/modules/IPsec"],
     srcs: [
-        "core/java/android/annotation/StringDef.java",
         "core/java/android/net/annotations/PolicyDirection.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IState.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
+        "services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java",
         "telephony/java/android/telephony/Annotation.java",
     ],
 }
@@ -691,45 +422,22 @@
     srcs: [
         // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
         ":framework-annotations",
+        ":modules-utils-preconditions-srcs",
         "core/java/android/net/DhcpResults.java",
+        "core/java/android/util/IndentingPrintWriter.java",
         "core/java/android/util/LocalLog.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/IState.java",
         "core/java/com/android/internal/util/MessageUtils.java",
-        "core/java/com/android/internal/util/Preconditions.java",
         "core/java/com/android/internal/util/RingBufferIndices.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "core/java/com/android/internal/util/TokenBucket.java",
     ],
 }
 
-filegroup {
-    name: "framework-services-net-module-wifi-shared-srcs",
-    srcs: [
-        "core/java/android/net/DhcpResults.java",
-        "core/java/android/net/util/IpUtils.java",
-        "core/java/android/util/LocalLog.java",
-    ],
-}
-
-// keep these files in sync with the package/Tethering/jarjar-rules.txt for the tethering module.
-filegroup {
-    name: "framework-tethering-shared-srcs",
-    srcs: [
-        "core/java/android/util/LocalLog.java",
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/MessageUtils.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/TrafficStatsConstants.java",
-    ],
-}
-
 // Build ext.jar
 // ============================================================
 java_library {
@@ -744,525 +452,138 @@
     dxflags: ["--core-library"],
 }
 
-// ====  java proto host library  ==============================
-java_library_host {
-    name: "platformprotos",
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "cmds/am/proto/instrumentation_data.proto",
-        "cmds/statsd/src/**/*.proto",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/**/*.proto",
-    ],
-    proto: {
-        include_dirs: ["external/protobuf/src"],
-        type: "full",
-    },
-    errorprone: {
-        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
-    },
-}
-
-// ====  java proto device library (for test only)  ==============================
-java_library {
-    name: "platformprotosnano",
-    proto: {
-        type: "nano",
-        output_params: ["store_unknown_fields=true"],
-        include_dirs: ["external/protobuf/src"],
-    },
-    exclude_srcs: [
-        "core/proto/android/privacy.proto",
-        "core/proto/android/section.proto",
-    ],
-    sdk_version: "9",
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/android/os/**/*.proto",
-    ],
-}
-
-// ====  java proto device library (for test only)  ==============================
-java_library {
-    name: "platformprotoslite",
-    proto: {
-        type: "lite",
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "core/proto/**/*.proto",
-        "libs/incident/proto/android/os/**/*.proto",
-    ],
-    exclude_srcs: [
-        "core/proto/android/privacy.proto",
-        "core/proto/android/section.proto",
-    ],
-    sdk_version: "core_current",
-    // Protos have lots of MissingOverride and similar.
-    errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
-    },
-}
-
-// ====  c++ proto device library  ==============================
-cc_defaults {
-    name: "libplatformprotos-defaults",
-
-    proto: {
-        export_proto_headers: true,
-        include_dirs: ["external/protobuf/src"],
-    },
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-    ],
-
-    srcs: [
-        ":ipconnectivity-proto-src",
-        "core/proto/**/*.proto",
-    ],
-}
-
-cc_library {
-    name: "libplatformprotos",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: true,
-
-    target: {
-        host: {
-            proto: {
-                type: "full",
-            },
-        },
-        android: {
-            proto: {
-                type: "lite",
-            },
-            shared_libs: [
-                "libprotobuf-cpp-lite",
-            ],
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-// This library is meant for vendor code that needs to output protobuf. It links
-// against the static version of libprotobuf-cpp-lite, for which we can not guarantee
-// binary compatibility.
-cc_library {
-    name: "libplatformprotos-static",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: false,
-
-    // This is okay because this library is only built as a static library.  The C++
-    // API is not guaranteed. The proto API is guaranteed to be stable via Metrics Council,
-    // but is not authorized to be used outside of debugging.
-    vendor_available: true,
-
-    target: {
-        android: {
-            proto: {
-                type: "lite",
-            },
-            static_libs: [
-                "libprotobuf-cpp-lite",
-            ],
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-
-// This is the full proto version of libplatformprotos. It may only
-// be used by test code that is not shipped on the device.
-cc_library {
-    name: "libplatformprotos-test",
-    defaults: ["libplatformprotos-defaults"],
-    host_supported: false,
-
-    target: {
-        android: {
-            proto: {
-                type: "full",
-            },
-            shared: {
-                enabled: false,
-            },
-        },
-    },
-}
-
-filegroup {
-    name: "incremental_aidl",
-    srcs: [
-        "core/java/android/os/incremental/IIncrementalServiceConnector.aidl",
-        "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "dataloader_aidl",
-    srcs: [
-        "core/java/android/content/pm/DataLoaderParamsParcel.aidl",
-        "core/java/android/content/pm/DataLoaderType.aidl",
-        "core/java/android/content/pm/FileSystemControlParcel.aidl",
-        "core/java/android/content/pm/IDataLoader.aidl",
-        "core/java/android/content/pm/IDataLoaderManager.aidl",
-        "core/java/android/content/pm/InstallationFileParcel.aidl",
-        "core/java/android/content/pm/InstallationFileLocation.aidl",
-        "core/java/android/content/pm/IDataLoaderStatusListener.aidl",
-        "core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl",
-    ],
-    path: "core/java",
-}
-
-filegroup {
-    name: "incremental_manager_aidl",
-    srcs: [
-        "core/java/android/os/incremental/IIncrementalService.aidl",
-        "core/java/android/os/incremental/IncrementalNewFileParams.aidl",
-        "core/java/android/os/incremental/IStorageHealthListener.aidl",
-        "core/java/android/os/incremental/StorageHealthCheckParams.aidl",
-    ],
-    path: "core/java",
-}
-
-aidl_interface {
-    name: "libincremental_aidl",
-    unstable: true,
-    srcs: [
-        ":incremental_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: true,
-        },
-    },
-}
-
-aidl_interface {
-    name: "libdataloader_aidl",
-    unstable: true,
-    srcs: [
-        ":dataloader_aidl",
-    ],
-    imports: [
-        "libincremental_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: false,
-        },
-    },
-}
-
-aidl_interface {
-    name: "libincremental_manager_aidl",
-    unstable: true,
-    srcs: [
-        ":incremental_manager_aidl",
-    ],
-    imports: [
-        "libincremental_aidl",
-        "libdataloader_aidl",
-    ],
-    backend: {
-        java: {
-            sdk_version: "28",
-        },
-        cpp: {
-            enabled: true,
-        },
-        ndk: {
-            enabled: false,
-        },
-    },
-}
-
-// TODO(b/77285514): remove this once the last few hidl interfaces have been
-// updated to use hwbinder.stubs.
-java_library {
-    name: "hwbinder",
-    sdk_version: "core_platform",
-
-    srcs: [
-        "core/java/android/os/HidlSupport.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/SystemApi.java",
-        "core/java/android/annotation/TestApi.java",
-        "core/java/android/os/HidlMemory.java",
-        "core/java/android/os/HwBinder.java",
-        "core/java/android/os/HwBlob.java",
-        "core/java/android/os/HwParcel.java",
-        "core/java/android/os/IHwBinder.java",
-        "core/java/android/os/IHwInterface.java",
-        "core/java/android/os/DeadObjectException.java",
-        "core/java/android/os/DeadSystemException.java",
-        "core/java/android/os/NativeHandle.java",
-        "core/java/android/os/RemoteException.java",
-        "core/java/android/util/AndroidException.java",
-    ],
-    libs: [ "unsupportedappusage" ],
-
-    dxflags: ["--core-library"],
-    installable: false,
-}
-
-python_defaults {
-    name: "base_default",
-    version: {
-        py2: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-        py3: {
-            enabled: false,
-            embedded_launcher: false,
-        },
-    },
-}
-
-python_binary_host {
-    name: "fontchain_linter",
-    defaults: ["base_default"],
-    main: "tools/fonts/fontchain_linter.py",
-    srcs: [
-        "tools/fonts/fontchain_linter.py",
-    ],
-    libs: [
-        "fontTools",
-    ],
-}
-
-filegroup {
-    name: "framework-media-annotation-srcs",
-    srcs: [
-        ":framework-annotations",
-        "core/java/android/annotation/CallbackExecutor.java",
-        "core/java/android/annotation/CallSuper.java",
-        "core/java/android/annotation/DrawableRes.java",
-        "core/java/android/annotation/LongDef.java",
-        "core/java/android/annotation/StringDef.java",
-    ],
-}
-
-filegroup {
-    name: "framework-mediaprovider-annotation-sources",
-    srcs: [
-        ":framework-annotations",
-        "core/java/android/annotation/BytesLong.java",
-        "core/java/android/annotation/CurrentTimeSecondsLong.java",
-        "core/java/android/annotation/DurationMillisLong.java",
-    ],
-}
-
-// Creates an index of AIDL methods; used for adding UnsupportedAppUsage
-// annotations to private apis
-aidl_mapping {
-    name: "framework-aidl-mappings",
-    srcs: [":framework-all-sources"],
-    output: "framework-aidl-mappings.txt",
-}
-
-// Avoid including Parcelable classes as we don't want to have two copies of
-// Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
-// and TeleService app (packages/services/Telephony).
-filegroup {
-    name: "framework-telephony-common-shared-srcs",
-    srcs: [
-        "core/java/android/os/BasicShellCommandHandler.java",
-        "core/java/android/os/RegistrantList.java",
-        "core/java/android/os/Registrant.java",
-        "core/java/android/util/LocalLog.java",
-        "core/java/android/util/TimeUtils.java",
-        "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/AsyncChannel.java",
-        "core/java/com/android/internal/util/AsyncService.java",
-        "core/java/com/android/internal/util/BitwiseInputStream.java",
-        "core/java/com/android/internal/util/FastXmlSerializer.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/UserIcons.java",
-    ],
-}
-
-// Avoid including Parcelable classes as we don't want to have two copies of
-// Parcelable cross the process. This is used by framework-telephony (frameworks/base/telephony).
-filegroup {
-    name: "framework-telephony-shared-srcs",
-    srcs: [
-        "core/java/android/util/RecurrenceRule.java",
-        "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/BitwiseInputStream.java",
-        "core/java/com/android/internal/util/BitwiseOutputStream.java",
-        "core/java/com/android/internal/util/FunctionalUtils.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-    ],
-}
-
-// Avoid including Parcelable classes as we don't want to have two copies of
-// Parcelable cross the process.
-filegroup {
-    name: "framework-cellbroadcast-shared-srcs",
-    srcs: [
-        "core/java/android/os/HandlerExecutor.java",
-        "core/java/android/util/LocalLog.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-    ],
-}
-
-filegroup {
-    name: "framework-ims-common-shared-srcs",
-    srcs: [
-        "core/java/android/os/RegistrantList.java",
-        "core/java/android/os/Registrant.java",
-        "core/java/com/android/internal/os/SomeArgs.java",
-        "core/java/com/android/internal/util/Preconditions.java",
-    ],
-}
-
 // utility classes statically linked into framework-wifi and dynamically linked
 // into wifi-service
 java_library {
     name: "framework-wifi-util-lib",
     sdk_version: "module_current",
+    min_sdk_version: "30",
     srcs: [
-        "core/java/android/content/pm/BaseParceledListSlice.java",
-        "core/java/android/content/pm/ParceledListSlice.java",
+        ":modules-utils-preconditions-srcs",
         "core/java/android/os/HandlerExecutor.java",
         "core/java/com/android/internal/util/AsyncChannel.java",
         "core/java/com/android/internal/util/AsyncService.java",
         "core/java/com/android/internal/util/Protocol.java",
-        "core/java/com/android/internal/util/Preconditions.java",
         "telephony/java/android/telephony/Annotation.java",
         ":net-utils-framework-wifi-common-srcs",
     ],
     libs: [
         "framework-annotations-lib",
+        "framework-connectivity.stubs.module_lib",
         "unsupportedappusage",
     ],
     visibility: [
         "//frameworks/base/wifi",
         "//frameworks/base/services/net",
+        "//packages/modules/Wifi/framework",
     ],
 }
 
-filegroup {
-    name: "framework-wifi-util-lib-aidls",
-    srcs: ["core/java/android/content/pm/ParceledListSlice.aidl"],
-    path: "core/java",
-}
-
-// utility classes statically linked into wifi-service
-filegroup {
-    name: "framework-wifi-service-shared-srcs",
-    srcs: [
-        "core/java/android/net/InterfaceConfiguration.java",
-        "core/java/android/os/BasicShellCommandHandler.java",
-        "core/java/android/util/BackupUtils.java",
-        "core/java/android/util/Rational.java",
-        "core/java/com/android/internal/util/FastXmlSerializer.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IState.java",
-        "core/java/com/android/internal/util/MessageUtils.java",
-        "core/java/com/android/internal/util/State.java",
-        "core/java/com/android/internal/util/StateMachine.java",
-        "core/java/com/android/internal/util/WakeupMessage.java",
-    ],
-    visibility: ["//frameworks/opt/net/wifi/service"],
-}
-
 // TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
-    "--ignore-classes-on-classpath " +
     "--hide-package com.android.server " +
+    "--hide-package android.audio.policy.configuration.V7_0 " +
     "--error UnhiddenSystemApi " +
     "--hide RequiresPermission " +
     "--hide CallbackInterface " +
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
+    "--error NoSettingsProvider " +
     "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " +
     "--api-lint-ignore-prefix android.icu. " +
     "--api-lint-ignore-prefix java. " +
     "--api-lint-ignore-prefix junit. " +
     "--api-lint-ignore-prefix org. "
 
+packages_to_document = [
+    "android",
+    "dalvik",
+    "java",
+    "javax",
+    "junit",
+    "org.apache.http",
+    "org.json",
+    "org.w3c.dom",
+    "org.xml.sax",
+    "org.xmlpull",
+]
+
+filegroup {
+    name: "android-non-updatable-stub-sources",
+    srcs: [
+        ":framework-mime-sources", // mimemap builds separately but has no separate droidstubs.
+        ":framework-non-updatable-sources",
+        ":opt-telephony-srcs",
+        ":opt-net-voip-srcs",
+        "core/java/**/*.logtags",
+        "**/package.html",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// These defaults are used for both the jar stubs and the doc stubs.
+stubs_defaults {
+    name: "android-non-updatable-stubs-defaults",
+    srcs: [":android-non-updatable-stub-sources"],
+    sdk_version: "none",
+    system_modules: "none",
+    java_version: "1.8",
+    arg_files: ["core/res/AndroidManifest.xml"],
+    // TODO(b/147699819): remove below aidl includes.
+    aidl: {
+        local_include_dirs: [
+            "apex/media/aidl/stable",
+            "media/aidl",
+            "telephony/java",
+        ],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+            "packages/modules/Connectivity/framework/aidl-export",
+        ],
+    },
+    // These are libs from framework-internal-utils that are required (i.e. being referenced)
+    // from framework-non-updatable-sources. Add more here when there's a need.
+    // DO NOT add the entire framework-internal-utils. It might cause unnecessary circular
+    // dependencies gets bigger.
+    libs: [
+        "android.hardware.cas-V1.2-java",
+        "android.hardware.health-V1.0-java-constants",
+        "android.hardware.radio-V1.5-java",
+        "android.hardware.radio-V1.6-java",
+        "android.hardware.thermal-V1.0-java-constants",
+        "android.hardware.thermal-V2.0-java",
+        "android.hardware.tv.input-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.1-java-constants",
+        "android.hardware.usb-V1.0-java-constants",
+        "android.hardware.usb-V1.1-java-constants",
+        "android.hardware.usb.gadget-V1.0-java",
+        "android.hardware.vibrator-V1.3-java",
+        "framework-protos",
+        "art.module.public.api",
+        // There are a few classes from modules used by the core that
+        // need to be resolved by metalava. We use a prebuilt stub of the
+        // full sdk to ensure we can resolve them. If a new class gets added,
+        // the prebuilts/sdk/current needs to be updated.
+        "sdk_system_current_android",
+        // NOTE: The below can be removed once the prebuilt stub contains IKE.
+        "sdk_system_current_android.net.ipsec.ike",
+    ],
+    filter_packages: packages_to_document,
+    high_mem: true, // Lots of sources => high memory use, see b/170701554
+    installable: false,
+    annotations_enabled: true,
+    previous_api: ":android.api.public.latest",
+    merge_annotations_dirs: ["metalava-manual"],
+    defaults_visibility: ["//visibility:private"],
+    visibility: ["//frameworks/base/api"],
+}
+
 build = [
     "StubLibraries.bp",
     "ApiDocs.bp",
+    "ProtoLibraries.bp",
+    "TestProtoLibraries.bp",
 ]
-
-java_library {
-    name: "framework-telephony",
-    srcs: [
-        //":framework-telephony-sources",
-        //":framework-telephony-shared-srcs",
-    ],
-    // TODO: change to framework-system-stub to build against system APIs.
-    libs: [
-        "framework-minus-apex",
-        "unsupportedappusage",
-    ],
-    static_libs: [
-        "libphonenumber-platform",
-        "app-compat-annotations",
-    ],
-    sdk_version: "core_platform",
-    aidl: {
-        export_include_dirs: ["telephony/java"],
-        include_dirs: [
-            "frameworks/native/aidl/binder",
-            "frameworks/native/aidl/gui",
-        ]
-    },
-    jarjar_rules: ":framework-telephony-jarjar-rules",
-    dxflags: [
-        "--core-library",
-        "--multi-dex",
-    ],
-    // This is to break the dependency from boot jars.
-    dex_preopt: {
-        enabled: false,
-    },
-    installable: true,
-}
-
-filegroup {
-    name: "framework-telephony-jarjar-rules",
-    srcs: ["telephony/framework-telephony-jarjar-rules.txt"],
-}
diff --git a/Android.mk b/Android.mk
index d3627e1..46529eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,10 +32,6 @@
 # ============================================================
 include $(CLEAR_VARS)
 
-# This is used by ide.mk as the list of source files that are
-# always included.
-INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
-
 # sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
 # So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
 # $(OUT_DOCS)/offline-sdk.
@@ -60,7 +56,7 @@
 $(SDK_METADATA): $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/framework-doc-stubs-metadata.zip
 	rm -rf $(SDK_METADATA_DIR)
 	mkdir -p $(SDK_METADATA_DIR)
-	unzip -qo $< -d $(SDK_METADATA_DIR)
+	unzip -DDqo $< -d $(SDK_METADATA_DIR)
 
 .PHONY: framework-doc-stubs
 framework-doc-stubs: $(SDK_METADATA)
diff --git a/ApiDocs.bp b/ApiDocs.bp
index a81342a..aae4a71 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -56,24 +56,51 @@
 ]
 
 stubs_defaults {
-    name: "framework-doc-stubs-default",
+    name: "android-non-updatable-doc-stubs-defaults",
+    defaults: ["android-non-updatable-stubs-defaults"],
     srcs: [
-        ":framework-mime-sources",
-        ":framework-non-updatable-sources",
-        ":framework-updatable-sources",
-        "core/java/**/*.logtags",
+        // No longer part of the stubs, but are included in the docs.
         "test-base/src/**/*.java",
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        ":art-module-public-api-stubs-source",
-        ":conscrypt.module.public.api{.public.stubs.source}",
-        ":android_icu4j_public_api_files",
         "test-mock/src/**/*.java",
         "test-runner/src/**/*.java",
     ],
     libs: framework_docs_only_libs,
     create_doc_stubs: true,
+    write_sdk_values: true,
+}
+
+stubs_defaults {
+    name: "framework-doc-stubs-default",
+    srcs: [
+        ":android-non-updatable-stub-sources",
+
+        // Module sources
+        ":art.module.public.api{.public.stubs.source}",
+        ":conscrypt.module.public.api{.public.stubs.source}",
+        ":framework-appsearch-sources",
+        ":framework-connectivity-sources",
+        ":framework-graphics-srcs",
+        ":framework-mediaprovider-sources",
+        ":framework-permission-sources",
+        ":framework-permission-s-sources",
+        ":framework-scheduling-sources",
+        ":framework-sdkextensions-sources",
+        ":framework-statsd-sources",
+        ":framework-tethering-srcs",
+        ":framework-wifi-updatable-sources",
+        ":i18n.module.public.api{.public.stubs.source}",
+        ":ike-srcs",
+        ":updatable-media-srcs",
+
+        // No longer part of the stubs, but are included in the docs.
+        ":android-test-base-sources",
+        ":android-test-mock-sources",
+        ":android-test-runner-sources",
+    ],
+    libs: framework_docs_only_libs,
+    create_doc_stubs: true,
     annotations_enabled: true,
+    filter_packages: packages_to_document,
     api_levels_annotations_enabled: true,
     api_levels_annotations_dirs: [
         "sdk-dir",
@@ -83,6 +110,27 @@
     merge_annotations_dirs: [
         "metalava-manual",
     ],
+    // TODO(b/169090544): remove below aidl includes.
+    aidl: {
+        local_include_dirs: ["media/aidl"],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+        ],
+    },
+}
+
+droidstubs {
+    name: "android-non-updatable-doc-stubs",
+    defaults: ["android-non-updatable-doc-stubs-defaults"],
+    args: metalava_framework_docs_args,
+}
+
+droidstubs {
+    name: "android-non-updatable-doc-stubs-system",
+    defaults: ["android-non-updatable-doc-stubs-defaults"],
+    args: metalava_framework_docs_args +
+        " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
 }
 
 droidstubs {
@@ -101,7 +149,8 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
+    args: metalava_framework_docs_args +
+        " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
     write_sdk_values: true,
 }
 
@@ -131,7 +180,7 @@
     ],
     knowntags: [
         "docs/knowntags.txt",
-        ":known-oj-tags",
+        ":art.module.public.api{.doctags}",
     ],
     custom_template: "droiddoc-templates-sdk",
     resourcesdir: "docs/html/reference/images/",
@@ -150,12 +199,18 @@
         ":current-support-api",
         ":current-androidx-api",
     ],
-    create_stubs: false,
+    // TODO(b/169090544): remove below aidl includes.
+    aidl: {
+        local_include_dirs: ["media/aidl"],
+        include_dirs: [
+            "frameworks/av/aidl",
+            "frameworks/native/libs/permission/aidl",
+        ],
+    },
 }
 
 doc_defaults {
     name: "framework-dokka-docs-default",
-    create_stubs: false,
 }
 
 droiddoc {
@@ -320,7 +375,7 @@
         ":framework-doc-stubs",
     ],
     args: "-noJdkLink -links https://kotlinlang.org/api/latest/jvm/stdlib/^external/dokka/package-list " +
-    "-noStdlibLink",
+        "-noStdlibLink",
     proofread_file: "ds-dokka-proofread.txt",
     dokka_enabled: true,
 }
@@ -340,7 +395,7 @@
         targets: ["docs"],
     },
     cmd: "$(location zip2zip) -i $(location :ds-docs-kt{.docs.zip}) -o $(genDir)/ds-docs-kt-moved.zip **/*:en/reference/kotlin && " +
-         "$(location merge_zips) $(out) $(location :ds-docs-java{.docs.zip}) $(genDir)/ds-docs-kt-moved.zip",
+        "$(location merge_zips) $(out) $(location :ds-docs-java{.docs.zip}) $(genDir)/ds-docs-kt-moved.zip",
 }
 
 java_genrule {
@@ -357,11 +412,11 @@
     dist: {
         targets: ["docs"],
     },
-    cmd: "unzip $(location :ds-docs-java{.docs.zip}) -d $(genDir) && " +
-         "unzip $(location :ds-docs-kt{.docs.zip}) -d $(genDir)/en/reference/kotlin && " +
-         "SWITCHER=$$(cd $$(dirname $(location switcher4)) && pwd)/$$(basename $(location switcher4)) && " +
-         "(cd $(genDir)/en/reference && $$SWITCHER --work platform) && " +
-         "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)",
+    cmd: "unzip -q $(location :ds-docs-java{.docs.zip}) -d $(genDir) && " +
+        "unzip -q $(location :ds-docs-kt{.docs.zip}) -d $(genDir)/en/reference/kotlin && " +
+        "SWITCHER=$$(cd $$(dirname $(location switcher4)) && pwd)/$$(basename $(location switcher4)) && " +
+        "(cd $(genDir)/en/reference && $$SWITCHER --work platform) > /dev/null && " +
+        "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)",
 }
 
 droiddoc {
@@ -373,7 +428,6 @@
     hdf: [
         "android.whichdoc online",
     ],
-    proofread_file: "ds-static-docs-proofrerad.txt",
     args: framework_docs_only_args +
         " -staticonly " +
         " -toroot / " +
@@ -390,7 +444,6 @@
     hdf: [
         "android.whichdoc online",
     ],
-    proofread_file: "ds-ref-navtree-docs-proofrerad.txt",
     args: framework_docs_only_args +
         " -toroot / " +
         " -atLinksNavtree " +
@@ -437,4 +490,3 @@
         " -referenceonly " +
         " -title \"Android SDK - Including hidden APIs.\"",
 }
-
diff --git a/BATTERY_STATS_OWNERS b/BATTERY_STATS_OWNERS
new file mode 100644
index 0000000..7728975
--- /dev/null
+++ b/BATTERY_STATS_OWNERS
@@ -0,0 +1,4 @@
+# OWNERS of BatteryStats related files
+bookatz@google.com
+dplotnikov@google.com
+mwachens@google.com
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..95577d8
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,4 @@
+third_party {
+  # would be NOTICE save for libs/usb/tests/accessorytest/f_accessory.h
+  license_type: RESTRICTED
+}
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
new file mode 100644
index 0000000..fbc611a
--- /dev/null
+++ b/MULTIUSER_OWNERS
@@ -0,0 +1,4 @@
+# OWNERS of Multiuser related files
+bookatz@google.com
+omakoto@google.com
+yamasani@google.com
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..4970dd1
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,33 @@
+# This top-level list should remain narrowly defined as team leads; individual
+# teams are strongly encouraged to define narrower OWNERS files at deeper
+# levels within the source tree; see OWNERS.md for more details
+akulian@google.com
+dsandler@android.com
+dsandler@google.com
+hackbod@android.com
+hackbod@google.com
+jjaggi@google.com
+jsharkey@android.com
+jsharkey@google.com
+lorenzo@google.com
+michaelwr@google.com
+nandana@google.com
+narayan@google.com
+ogunwale@google.com
+roosa@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+yamasani@google.com
+
+# API changes are already covered by API-Review+1 (http://mdb/android-api-council)
+# via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
+per-file */api/*current.txt = *
+
+# Support bulk translation updates
+per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
+
+per-file Android.bp = file:platform/build/soong:/OWNERS
+per-file Android.mk = file:platform/build/soong:/OWNERS
+per-file ApiDocs.bp = file:platform/build/soong:/OWNERS
+per-file StubLibraries.bp = file:platform/build/soong:/OWNERS
+per-file ProtoLibraries.bp = file:platform/build/soong:/OWNERS
diff --git a/OWNERS.md b/OWNERS.md
new file mode 100644
index 0000000..601b5c64
--- /dev/null
+++ b/OWNERS.md
@@ -0,0 +1,68 @@
+# Background
+
+As general background, `OWNERS` files expedite code reviews by helping code
+authors quickly find relevant reviewers, and they also ensure that stakeholders
+are involved in code changes in their areas.
+
+The structure of `frameworks/base/` is unique among Android repositories, and
+it's evolved into a complex interleaved structure over the years.  Because of
+this structure, the best place to authoritatively define `OWNERS` can vary
+wildly, but here are some common patterns:
+
+* `core/java/` contains source that is included in the base classpath, and as
+such it's where most APIs are defined:
+  * `core/java/android/app/`
+  * `core/java/android/content/`
+* `services/core/` contains most system services, and these directories
+typically have more granularity than `core/java/`, since they can be refactored
+without API changes:
+  * `services/core/java/com/android/server/net/`
+  * `services/core/java/com/android/server/wm/`
+* `services/` contains several system services that have been isolated from the
+main `services/core/` project:
+  * `services/appwidget/`
+  * `services/midi/`
+* `apex/` contains Mainline modules:
+  * `apex/jobscheduler/`
+  * `apex/permission/`
+* Finally, some teams may have dedicated top-level directories:
+  * `media/`
+  * `wifi/`
+
+# Design
+
+Area maintainers are strongly encouraged to list people in a single
+authoritative `OWNERS` file in **exactly one** location.  Then, other paths
+should reference that single authoritative `OWNERS` file using an include
+directive.  This approach ensures that updates are applied consistently across
+the tree, reducing maintenance burden.
+
+# Examples
+
+The exact syntax of `OWNERS` files can be difficult to get correct, so here are
+some common examples:
+
+```
+# Complete include of top-level owners from this repo
+include /ZYGOTE_OWNERS
+# Partial include of top-level owners from this repo
+per-file ZygoteFile.java = file:/ZYGOTE_OWNERS
+```
+```
+# Complete include of subdirectory owners from this repo
+include /services/core/java/com/android/server/net/OWNERS
+# Partial include of subdirectory owners from this repo
+per-file NetworkFile.java = file:/services/core/java/com/android/server/net/OWNERS
+```
+```
+# Complete include of top-level owners from another repo
+include platform/libcore:/OWNERS
+# Partial include of top-level owners from another repo
+per-file LibcoreFile.java = file:platform/libcore:/OWNERS
+```
+```
+# Complete include of subdirectory owners from another repo
+include platform/frameworks/av:/camera/OWNERS
+# Partial include of subdirectory owners from another repo
+per-file CameraFile.java = file:platform/frameworks/av:/camera/OWNERS
+```
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2fd2e33..65b2511 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,22 +1,28 @@
 [Builtin Hooks]
 clang_format = true
+bpfmt = true
 
 [Builtin Hooks Options]
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/hid/
                cmds/input/
+               cmds/uinput/
                core/jni/
+               libs/hwui/
                libs/input/
+               native/
                services/core/jni/
                services/incremental/
-
+               tests/
+               tools/
+bpfmt = -d
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 
 strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
 
-hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
+hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
 hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
new file mode 100644
index 0000000..7e3cc27
--- /dev/null
+++ b/ProtoLibraries.bp
@@ -0,0 +1,253 @@
+// Copyright (C) 2021 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.
+
+gensrcs {
+    name: "framework-javastream-protos",
+    depfile: true,
+
+    tools: [
+        "aprotoc",
+        "protoc-gen-javastream",
+        "soong_zip",
+    ],
+
+    cmd: "mkdir -p $(genDir)/$(in) " +
+        "&& $(location aprotoc) " +
+        "  --plugin=$(location protoc-gen-javastream) " +
+        "  --dependency_out=$(depfile) " +
+        "  --javastream_out=$(genDir)/$(in) " +
+        "  -Iexternal/protobuf/src " +
+        "  -I . " +
+        "  $(in) " +
+        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        ":libtombstone_proto-src",
+        "core/proto/**/*.proto",
+        "libs/incident/**/*.proto",
+        ":service-permission-protos",
+    ],
+    output_extension: "srcjar",
+}
+
+gensrcs {
+    name: "framework-cppstream-protos",
+    depfile: true,
+
+    tools: [
+        "aprotoc",
+        "protoc-gen-cppstream",
+    ],
+
+    cmd: "mkdir -p $(genDir) " +
+        "&& $(location aprotoc) " +
+        "  --plugin=$(location protoc-gen-cppstream) " +
+        "  --dependency_out=$(depfile) " +
+        "  --cppstream_out=$(genDir) " +
+        "  -Iexternal/protobuf/src " +
+        "  -I . " +
+        "  $(in)",
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/**/*.proto",
+        ":service-permission-protos",
+    ],
+
+    output_extension: "proto.h",
+}
+
+// ====  java proto host library  ==============================
+java_library_host {
+    name: "platformprotos",
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        ":libstats_internal_protos",
+        ":statsd_internal_protos",
+        "cmds/am/proto/instrumentation_data.proto",
+        "cmds/statsd/src/**/*.proto",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/**/*.proto",
+        ":service-permission-protos",
+    ],
+    proto: {
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
+        type: "full",
+    },
+    // Protos have lots of MissingOverride and similar.
+    errorprone: {
+        javacflags: ["-XepDisableAllChecks"],
+    },
+}
+
+// ====  java proto device library (for test only)  ==============================
+java_library {
+    name: "platformprotosnano",
+    proto: {
+        type: "nano",
+        output_params: ["store_unknown_fields=true"],
+        include_dirs: ["external/protobuf/src"],
+    },
+    exclude_srcs: [
+        "core/proto/android/privacy.proto",
+        "core/proto/android/section.proto",
+        "core/proto/android/typedef.proto",
+    ],
+    sdk_version: "9",
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/android/os/**/*.proto",
+        ":service-permission-protos",
+    ],
+}
+
+// ====  java proto device library (for test only)  ==============================
+java_library {
+    name: "platformprotoslite",
+    proto: {
+        type: "lite",
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/android/os/**/*.proto",
+        ":service-permission-protos",
+    ],
+    exclude_srcs: [
+        "core/proto/android/privacy.proto",
+        "core/proto/android/section.proto",
+        "core/proto/android/typedef.proto",
+    ],
+    sdk_version: "core_current",
+    // Protos have lots of MissingOverride and similar.
+    errorprone: {
+        javacflags: ["-XepDisableAllChecks"],
+    },
+}
+
+// ====  c++ proto device library  ==============================
+cc_defaults {
+    name: "libplatformprotos-defaults",
+
+    proto: {
+        export_proto_headers: true,
+        include_dirs: [
+            "external/protobuf/src",
+        ],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+
+    srcs: [
+        ":ipconnectivity-proto-src",
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        "core/proto/**/*.proto",
+        ":service-permission-protos",
+    ],
+}
+
+cc_library {
+    name: "libplatformprotos",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: true,
+
+    target: {
+        host: {
+            proto: {
+                type: "full",
+            },
+        },
+        android: {
+            proto: {
+                type: "lite",
+            },
+            shared_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
+
+// This library is meant for vendor code that needs to output protobuf. It links
+// against the static version of libprotobuf-cpp-lite, for which we can not guarantee
+// binary compatibility.
+cc_library {
+    name: "libplatformprotos-static",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: false,
+
+    // This is okay because this library is only built as a static library.  The C++
+    // API is not guaranteed. The proto API is guaranteed to be stable via Metrics Council,
+    // but is not authorized to be used outside of debugging.
+    vendor_available: true,
+
+    target: {
+        android: {
+            proto: {
+                type: "lite",
+            },
+            static_libs: [
+                "libprotobuf-cpp-lite",
+            ],
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
+
+// This is the full proto version of libplatformprotos. It may only
+// be used by test code that is not shipped on the device.
+cc_library {
+    name: "libplatformprotos-test",
+    defaults: ["libplatformprotos-defaults"],
+    host_supported: false,
+
+    target: {
+        android: {
+            proto: {
+                type: "full",
+            },
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 3eb482d..44c55c2 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -16,396 +16,421 @@
 //
 // raw source files --(metalava)--> stub source files --(javac)--> stub jar files
 //
-// The metalava conversion is done by droidstub modules *-api-stubs-docs.
-// The javac compilation is done by java_library modules android_*_stubs_current.
+// - The metalava conversion is done by droidstub modules
+// - The javac compilation is done by java_library modules
+//
 // The metalava conversion is also responsible for creating API signature files
-// and comparing them against the last API signature in api/*-current.txt files
-// and also against the latest frozen API signature in prebuilts/sdk/*/*/api/android.txt
-// files.
+// and comparing them against the checked in API signature, and also checking compatibility
+// with the latest frozen API signature.
 
 /////////////////////////////////////////////////////////////////////
 // Common metalava configs
 /////////////////////////////////////////////////////////////////////
 
-packages_to_document = [
-    "android",
-    "dalvik",
-    "java",
-    "javax",
-    "junit",
-    "org.apache.http",
-    "org.json",
-    "org.w3c.dom",
-    "org.xml.sax",
-    "org.xmlpull",
-]
-
-stubs_defaults {
-    name: "metalava-base-api-stubs-default",
-    srcs: [
-        ":framework-non-updatable-sources",
-        "core/java/**/*.logtags",
-        ":opt-telephony-srcs",
-        ":opt-net-voip-srcs",
-        ":art-module-public-api-stubs-source",
-        ":android_icu4j_public_api_files",
-    ],
-    // TODO(b/147699819): remove below aidl includes.
-    aidl: {
-        local_include_dirs: ["telephony/java"],
-    },
-    libs: ["framework-internal-utils"],
-    installable: false,
-    annotations_enabled: true,
-    previous_api: ":android.api.public.latest",
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    api_levels_annotations_enabled: false,
-    filter_packages: packages_to_document,
-}
-
-stubs_defaults {
-    name: "metalava-full-api-stubs-default",
-    defaults: ["metalava-base-api-stubs-default"],
-    srcs: [
-        ":conscrypt.module.public.api{.public.stubs.source}",
-        ":framework-updatable-sources",
-    ],
-    sdk_version: "core_platform",
-}
-
 stubs_defaults {
     name: "metalava-non-updatable-api-stubs-default",
-    defaults: ["metalava-base-api-stubs-default"],
-    sdk_version: "core_platform",
-    // There are a few classes from modules used as type arguments that
-    // need to be resolved by metalava. For now, we can use a previously
-    // finalized stub library to resolve them. If a new class gets added,
-    // this may be need to be revisited to use a manually maintained stub
-    // library with empty classes in order to resolve those references.
-    libs: ["sdk_system_30_android"],
-    aidl: {
-        local_include_dirs: ["apex/media/aidl/stable"],
-    },
+    defaults: ["android-non-updatable-stubs-defaults"],
+    api_levels_annotations_enabled: false,
+    defaults_visibility: ["//visibility:private"],
 }
 
 /////////////////////////////////////////////////////////////////////
-// *-api-stubs-docs modules providing source files for the stub libraries
+// These modules provide source files for the stub libraries
 /////////////////////////////////////////////////////////////////////
 
-// api-stubs-docs, system-api-stubs-docs, and test-api-stubs-docs have APIs
-// from the non-updatable part of the platform as well as from the updatable
-// modules
-droidstubs {
-    name: "api-stubs-docs",
-    defaults: ["metalava-full-api-stubs-default"],
-    removed_dex_api_filename: "removed-dex.txt",
-    arg_files: [
-        "core/res/AndroidManifest.xml",
-    ],
-    args: metalava_framework_docs_args,
-    check_api: {
-        current: {
-            api_file: "api/current.txt",
-            removed_api_file: "api/removed.txt",
-        },
-        last_released: {
-            api_file: ":android.api.public.latest",
-            removed_api_file: ":removed.api.public.latest",
-            baseline_file: ":public-api-incompatibilities-with-last-released",
-        },
-        api_lint: {
-            enabled: true,
-            new_since: ":android.api.public.latest",
-            baseline_file: "api/lint-baseline.txt",
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/public/api",
-        dest: "android.txt",
-    },
-    jdiff_enabled: true,
-}
-
 droidstubs {
     name: "api-stubs-docs-non-updatable",
     defaults: ["metalava-non-updatable-api-stubs-default"],
-    arg_files: ["core/res/AndroidManifest.xml"],
     args: metalava_framework_docs_args,
     check_api: {
         current: {
-            api_file: "non-updatable-api/current.txt",
-            removed_api_file: "non-updatable-api/removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-            new_since: ":android-non-updatable.api.public.latest",
-        },
-    },
-}
-
-priv_apps = " " +
-    "--show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
-    "\\) "
-
-module_libs = " " +
-    " --show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
-    "\\) "
-
-droidstubs {
-    name: "system-api-stubs-docs",
-    defaults: ["metalava-full-api-stubs-default"],
-    removed_dex_api_filename: "system-removed-dex.txt",
-    arg_files: [
-        "core/res/AndroidManifest.xml",
-    ],
-    args: metalava_framework_docs_args + priv_apps,
-    check_api: {
-        current: {
-            api_file: "api/system-current.txt",
-            removed_api_file: "api/system-removed.txt",
+            api_file: "core/api/current.txt",
+            removed_api_file: "core/api/removed.txt",
         },
         last_released: {
-            api_file: ":android.api.system.latest",
-            removed_api_file: ":removed.api.system.latest",
-            baseline_file: ":system-api-incompatibilities-with-last-released"
+            api_file: ":android-non-updatable.api.public.latest",
+            removed_api_file: ":android-non-updatable-removed.api.public.latest",
+            baseline_file: ":android-non-updatable-incompatibilities.api.public.latest",
         },
         api_lint: {
             enabled: true,
-            new_since: ":android.api.system.latest",
-            baseline_file: "api/system-lint-baseline.txt",
+            new_since: ":android.api.public.latest",
         },
     },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system/api",
-        dest: "android.txt",
-    },
-    jdiff_enabled: true,
+    dists: [
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/public/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/public/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
+priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+    "\\)"
+
+priv_apps_in_stubs = " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+    "\\)"
+
+test = " --show-annotation android.annotation.TestApi"
+
+module_libs = " --show-annotation android.annotation.SystemApi\\(" +
+    "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+    "\\)"
+
 droidstubs {
     name: "system-api-stubs-docs-non-updatable",
     defaults: ["metalava-non-updatable-api-stubs-default"],
-    arg_files: ["core/res/AndroidManifest.xml"],
     args: metalava_framework_docs_args + priv_apps,
     check_api: {
         current: {
-            api_file: "non-updatable-api/system-current.txt",
-            removed_api_file: "non-updatable-api/system-removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-            new_since: ":android-non-updatable.api.system.latest",
-            baseline_file: "non-updatable-api/system-lint-baseline.txt",
-        },
-    },
-}
-
-droidstubs {
-    name: "test-api-stubs-docs",
-    defaults: ["metalava-full-api-stubs-default"],
-    arg_files: [
-        "core/res/AndroidManifest.xml",
-    ],
-    args: metalava_framework_docs_args + " --show-annotation android.annotation.TestApi",
-    check_api: {
-        current: {
-            api_file: "api/test-current.txt",
-            removed_api_file: "api/test-removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-            baseline_file: "api/test-lint-baseline.txt",
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/test/api",
-        dest: "android.txt",
-    },
-}
-
-/////////////////////////////////////////////////////////////////////
-// Following droidstubs modules are for extra APIs for modules.
-// The framework currently have two more API surfaces for modules:
-// @SystemApi(client=MODULE_APPS) and @SystemApi(client=MODULE_LIBRARIES)
-/////////////////////////////////////////////////////////////////////
-
-// TODO(b/146727827) remove the *-api module when we can teach metalava
-// about the relationship among the API surfaces. Currently, these modules are only to generate
-// the API signature files and ensure that the APIs evolve in a backwards compatible manner.
-// They however are NOT used for building the API stub.
-
-droidstubs {
-    name: "module-lib-api",
-    defaults: ["metalava-full-api-stubs-default"],
-    arg_files: ["core/res/AndroidManifest.xml"],
-    args: metalava_framework_docs_args + module_libs,
-    check_api: {
-        current: {
-            api_file: "api/module-lib-current.txt",
-            removed_api_file: "api/module-lib-removed.txt",
+            api_file: "core/api/system-current.txt",
+            removed_api_file: "core/api/system-removed.txt",
         },
         last_released: {
-            api_file: ":android.api.module-lib.latest",
-            removed_api_file: ":removed.api.module-lib.latest",
-            baseline_file: ":module-lib-api-incompatibilities-with-last-released"
+            api_file: ":android-non-updatable.api.system.latest",
+            removed_api_file: ":android-non-updatable-removed.api.system.latest",
+            baseline_file: ":android-non-updatable-incompatibilities.api.system.latest",
         },
         api_lint: {
             enabled: true,
-            new_since: ":android.api.module-lib.latest",
-            baseline_file: "api/module-lib-lint-baseline.txt",
+            new_since: ":android.api.system.latest",
+            baseline_file: "core/api/system-lint-baseline.txt",
         },
     },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/module-lib/api",
-        dest: "android.txt",
+    dists: [
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/system/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/system/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
+}
+
+droidstubs {
+    name: "test-api-stubs-docs-non-updatable",
+    defaults: ["metalava-non-updatable-api-stubs-default"],
+    args: metalava_framework_docs_args + test + priv_apps_in_stubs,
+    check_api: {
+        current: {
+            api_file: "core/api/test-current.txt",
+            removed_api_file: "core/api/test-removed.txt",
+        },
+        api_lint: {
+            enabled: true,
+            baseline_file: "core/api/test-lint-baseline.txt",
+        },
     },
+    dists: [
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/test/api",
+            dest: "android.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/test/api",
+            dest: "removed.txt",
+            tag: ".removed-api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/test/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/test/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 droidstubs {
     name: "module-lib-api-stubs-docs-non-updatable",
     defaults: ["metalava-non-updatable-api-stubs-default"],
-    arg_files: ["core/res/AndroidManifest.xml"],
-    args: metalava_framework_docs_args + module_libs,
+    args: metalava_framework_docs_args + priv_apps_in_stubs + module_libs,
     check_api: {
         current: {
-            api_file: "non-updatable-api/module-lib-current.txt",
-            removed_api_file: "non-updatable-api/module-lib-removed.txt",
+            api_file: "core/api/module-lib-current.txt",
+            removed_api_file: "core/api/module-lib-removed.txt",
+        },
+        last_released: {
+            api_file: ":android-non-updatable.api.module-lib.latest",
+            removed_api_file: ":android-non-updatable-removed.api.module-lib.latest",
         },
         api_lint: {
             enabled: true,
-            new_since: ":android-non-updatable.api.module-lib.latest",
+            new_since: ":android.api.module-lib.latest",
+            baseline_file: "core/api/module-lib-lint-baseline.txt",
         },
     },
-}
-
-// The following droidstub module generates source files for the API stub library for
-// modules. Note that it not only includes its own APIs but also other APIs that have
-// narrower scope (all @SystemApis, not just the ones with 'client=MODULE_LIBRARIES').
-
-droidstubs {
-    name: "module-lib-api-stubs-docs",
-    defaults: ["metalava-non-updatable-api-stubs-default"],
-    arg_files: ["core/res/AndroidManifest.xml"],
-    args: metalava_framework_docs_args + priv_apps + module_libs,
+    dists: [
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/module-lib/api",
+            dest: "android-non-updatable.txt",
+            tag: ".api.txt",
+        },
+        {
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            dir: "apistubs/android/module-lib/api",
+            dest: "android-non-updatable-removed.txt",
+            tag: ".removed-api.txt",
+        },
+    ],
 }
 
 /////////////////////////////////////////////////////////////////////
 // android_*_stubs_current modules are the stubs libraries compiled
-// from *-api-stubs-docs
+// from stub sources
 /////////////////////////////////////////////////////////////////////
 
+modules_public_stubs = [
+    "android.net.ipsec.ike.stubs",
+    "art.module.public.api.stubs",
+    "conscrypt.module.public.api.stubs",
+    "framework-appsearch.stubs",
+    "framework-connectivity.stubs",
+    "framework-graphics.stubs",
+    "framework-media.stubs",
+    "framework-mediaprovider.stubs",
+    "framework-permission.stubs",
+    "framework-permission-s.stubs",
+    "framework-scheduling.stubs",
+    "framework-sdkextensions.stubs",
+    "framework-statsd.stubs",
+    "framework-tethering.stubs",
+    "framework-wifi.stubs",
+    "i18n.module.public.api.stubs",
+]
+
+modules_system_stubs = [
+    "android.net.ipsec.ike.stubs.system",
+    "art.module.public.api.stubs.system",
+    "conscrypt.module.public.api.stubs", // Only has public stubs
+    "framework-appsearch.stubs.system",
+    "framework-connectivity.stubs.system",
+    "framework-graphics.stubs.system",
+    "framework-media.stubs.system",
+    "framework-mediaprovider.stubs.system",
+    "framework-permission.stubs.system",
+    "framework-permission-s.stubs.system",
+    "framework-scheduling.stubs.system",
+    "framework-sdkextensions.stubs.system",
+    "framework-statsd.stubs.system",
+    "framework-tethering.stubs.system",
+    "framework-wifi.stubs.system",
+    "i18n.module.public.api.stubs", // Only has public stubs
+]
+
 java_defaults {
-    name: "android_defaults_stubs_current",
-    libs: [ "stub-annotations" ],
-    static_libs: [
-        "framework-res-package-jar", // Export package of framework-res
-    ],
-    errorprone: {
-        javacflags: [
-            "-XepDisableAllChecks",
-        ],
-    },
-    java_resources: [":notices-for-framework-stubs"],
+    name: "android-non-updatable_defaults_stubs_current",
+    libs: ["stub-annotations"],
+    static_libs: ["framework-res-package-jar"], // Export package of framework-res
     sdk_version: "none",
     system_modules: "none",
     java_version: "1.8",
     compile_dex: true,
+    dist: {
+        targets: [
+            "sdk",
+            "win_sdk",
+        ],
+        tag: ".jar",
+        dest: "android-non-updatable.jar",
+    },
+    defaults_visibility: ["//visibility:private"],
+    visibility: ["//visibility:private"],
 }
 
-java_library_static {
-    name: "android_monolith_stubs_current",
-    srcs: [ ":api-stubs-docs" ],
-    static_libs: [ "private-stub-annotations-jar" ],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_merged_stubs_current",
-    srcs: [ ":api-stubs-docs-non-updatable" ],
-    static_libs: [
-        "conscrypt.module.public.api.stubs",
-        "framework-media.stubs",
-        "framework-mediaprovider.stubs",
-        "framework-permission.stubs",
-        "framework-sdkextensions.stubs",
-        "framework-statsd.stubs",
-        "framework-tethering.stubs",
-        "framework-wifi.stubs",
-        "private-stub-annotations-jar",
-    ],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_stubs_current",
-    static_libs: ["android_merged_stubs_current"],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_system_monolith_stubs_current",
-    srcs: [ ":system-api-stubs-docs" ],
-    static_libs: [ "private-stub-annotations-jar" ],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_system_merged_stubs_current",
-    srcs: [ ":system-api-stubs-docs-non-updatable" ],
-    static_libs: [
-        "conscrypt.module.public.api.stubs",
-        "framework-media.stubs.system",
-        "framework-mediaprovider.stubs.system",
-        "framework-permission.stubs.system",
-        "framework-sdkextensions.stubs.system",
-        "framework-statsd.stubs.system",
-        "framework-tethering.stubs.system",
-        "framework-wifi.stubs.system",
-        "private-stub-annotations-jar",
-    ],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_system_stubs_current",
-    static_libs: ["android_system_merged_stubs_current"],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_test_stubs_current",
-    srcs: [ ":test-api-stubs-docs" ],
-    static_libs: [ "private-stub-annotations-jar" ],
-    defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
-    name: "android_module_lib_stubs_current",
-    srcs: [ ":module-lib-api-stubs-docs" ],
-    defaults: ["android_defaults_stubs_current"],
-    libs: ["sdk_system_29_android"],
-}
-
-java_library_static {
-    name: "android_non_updatable_stubs_current",
+java_library {
+    name: "android-non-updatable.stubs",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
     srcs: [":api-stubs-docs-non-updatable"],
-    defaults: ["android_defaults_stubs_current"],
-    libs: ["sdk_system_29_android"],
+    libs: modules_public_stubs,
+    dist: {
+        dir: "apistubs/android/public",
+    },
 }
 
-java_library_static {
-    name: "android_system_non_updatable_stubs_current",
+java_library {
+    name: "android-non-updatable.stubs.system",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
     srcs: [":system-api-stubs-docs-non-updatable"],
-    defaults: ["android_defaults_stubs_current"],
-    libs: ["sdk_system_29_android"],
+    libs: modules_system_stubs,
+    dist: {
+        dir: "apistubs/android/system",
+    },
+}
+
+java_library {
+    name: "android-non-updatable.stubs.module_lib",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [":module-lib-api-stubs-docs-non-updatable"],
+    libs: [
+        "sdk_system_current_android",
+        // NOTE: The below can be removed once the prebuilt stub contains IKE.
+        "sdk_system_current_android.net.ipsec.ike",
+    ],
+    dist: {
+        dir: "apistubs/android/module-lib",
+    },
+}
+
+java_library {
+    name: "android-non-updatable.stubs.test",
+    defaults: ["android-non-updatable_defaults_stubs_current"],
+    srcs: [":test-api-stubs-docs-non-updatable"],
+    libs: modules_system_stubs,
+    dist: {
+        dir: "apistubs/android/test",
+    },
+}
+
+java_defaults {
+    name: "android_stubs_dists_default",
+    dist: {
+        targets: [
+            "sdk",
+            "win_sdk",
+        ],
+        tag: ".jar",
+        dest: "android.jar",
+    },
+    defaults_visibility: ["//frameworks/base/services"],
+}
+
+java_library {
+    name: "android_stubs_current",
+    static_libs: modules_public_stubs + [
+        "android-non-updatable.stubs",
+        "private-stub-annotations-jar",
+    ],
+    defaults: ["android.jar_defaults"],
+}
+
+java_library {
+    name: "android_system_stubs_current",
+    static_libs: modules_system_stubs + [
+        "android-non-updatable.stubs.system",
+        "private-stub-annotations-jar",
+    ],
+    defaults: [
+        "android.jar_defaults",
+        "android_stubs_dists_default",
+    ],
+    dist: {
+        dir: "apistubs/android/system",
+    },
+    dists: [
+        {
+            // Legacy dist path
+            targets: [
+                "sdk",
+                "win_sdk",
+            ],
+            tag: ".jar",
+            dest: "android_system.jar",
+        },
+    ],
+}
+
+java_library {
+    name: "android_test_stubs_current",
+    // Modules do not have test APIs, but we want to include their SystemApis, like we include
+    // the SystemApi of framework-non-updatable-sources.
+    static_libs: modules_system_stubs + [
+        "android-non-updatable.stubs.test",
+        "private-stub-annotations-jar",
+    ],
+    defaults: [
+        "android.jar_defaults",
+        "android_stubs_dists_default",
+    ],
+    dist: {
+        dir: "apistubs/android/test",
+    },
+}
+
+java_library {
+    name: "android_module_lib_stubs_current",
+    defaults: [
+        "android.jar_defaults",
+        "android_stubs_dists_default",
+    ],
+    static_libs: [
+        "android-non-updatable.stubs.module_lib",
+        "art.module.public.api.stubs.module_lib",
+    ],
+    dist: {
+        dir: "apistubs/android/module-lib",
+    },
+}
+
+java_library {
+    name: "android_system_server_stubs_current",
+    defaults: ["android_stubs_dists_default"],
+    srcs: [":services-non-updatable-stubs"],
+    installable: false,
+    static_libs: [
+        "android_module_lib_stubs_current",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
+    java_version: "1.8",
+    dist: {
+        dir: "apistubs/android/system-server",
+    },
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -417,10 +442,6 @@
     name: "hwbinder-stubs-docs",
     srcs: [
         "core/java/android/os/HidlSupport.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/SystemApi.java",
         "core/java/android/os/HidlMemory.java",
         "core/java/android/os/HwBinder.java",
         "core/java/android/os/HwBlob.java",
@@ -433,6 +454,7 @@
         "core/java/android/os/RemoteException.java",
         "core/java/android/util/AndroidException.java",
     ],
+    libs: ["framework-annotations-lib"],
     installable: false,
     sdk_version: "core_platform",
     annotations_enabled: true,
@@ -441,38 +463,15 @@
         "metalava-manual",
     ],
     args: priv_apps,
+    visibility: ["//visibility:private"],
 }
 
-java_library_static {
+java_library {
     name: "hwbinder.stubs",
     sdk_version: "core_current",
+    libs: ["framework-annotations-lib"],
     srcs: [
         ":hwbinder-stubs-docs",
     ],
-}
-
-/////////////////////////////////////////////////////////////////////
-// api/*-current.txt files for use by modules in other directories
-// like the CTS test
-/////////////////////////////////////////////////////////////////////
-
-filegroup {
-    name: "frameworks-base-api-current.txt",
-    srcs: [
-        "api/current.txt",
-    ],
-}
-
-filegroup {
-    name: "frameworks-base-api-system-current.txt",
-    srcs: [
-        "api/system-current.txt",
-    ],
-}
-
-filegroup {
-    name: "frameworks-base-api-system-removed.txt",
-    srcs: [
-        "api/system-removed.txt",
-    ],
+    visibility: ["//visibility:public"],
 }
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2b12da2..c5c6012 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,4 +1,20 @@
 {
+  "presubmit-large": [
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ],
   "presubmit": [
     {
       "name": "FrameworksUiServicesTests",
@@ -39,7 +55,7 @@
       ]
     },
     {
-      "name": "FrameworksServicesTests",
+      "name": "FrameworkPermissionTests",
       "options": [
         {
           "include-annotation": "android.platform.test.annotations.Presubmit"
@@ -51,11 +67,82 @@
           "exclude-annotation": "org.junit.Ignore"
         }
       ]
+    },
+    {
+      "name": "FrameworksInProcessTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
     }
   ],
   "postsubmit-managedprofile-stress": [
     {
       "name": "ManagedProfileLifecycleStressTest"
     }
-  ]
+  ],
+ "auto-postsubmit": [
+   // Test tag for automotive targets. These are only running in postsubmit so as to harden the
+   // automotive targets to avoid introducing additional test flake and build time. The plan for
+   // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
+   // Additionally, this tag is used in targeted test suites to limit resource usage on the test
+   // infra during the hardening phase.
+   // TODO: this tag to be removed once the above is no longer an issue.
+   {
+     "name": "FrameworksUiServicesTests",
+     "options": [
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       }
+     ]
+   },
+   {
+     "name": "ExtServicesUnitTests",
+     "options": [
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       }
+     ]
+   },
+   {
+     "name": "TestablesTests",
+     "options": [
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       }
+     ]
+   },
+   {
+     "name": "FrameworksCoreTests",
+     "options": [
+       {
+         "include-annotation": "android.platform.test.annotations.Presubmit"
+       },
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       },
+       {
+         "exclude-annotation": "org.junit.Ignore"
+       }
+     ]
+   },
+   {
+     "name": "FrameworksServicesTests",
+     "options": [
+       {
+         "include-annotation": "android.platform.test.annotations.Presubmit"
+       },
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       },
+       {
+         "exclude-annotation": "org.junit.Ignore"
+       }
+     ]
+   }
+ ]
 }
diff --git a/TestProtoLibraries.bp b/TestProtoLibraries.bp
new file mode 100644
index 0000000..8e269d0
--- /dev/null
+++ b/TestProtoLibraries.bp
@@ -0,0 +1,36 @@
+// Copyright 2021 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.
+
+java_library_host {
+    name: "platformtestprotos",
+    srcs: [
+        ":libstats_atom_enum_protos",
+        ":libstats_atom_message_protos",
+        ":libstats_internal_protos",
+        ":statsd_internal_protos",
+    ],
+    libs: [
+        "libprotobuf-java-full",
+    ],
+    proto: {
+        include_dirs: [
+            "external/protobuf/src",
+            "frameworks/proto_logging/stats",
+        ],
+        type: "full",
+    },
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
+    },
+}
diff --git a/ZYGOTE_OWNERS b/ZYGOTE_OWNERS
new file mode 100644
index 0000000..90a185b
--- /dev/null
+++ b/ZYGOTE_OWNERS
@@ -0,0 +1,5 @@
+calin@google.com
+chriswailes@google.com
+maco@google.com
+narayan@google.com
+ngeoffray@google.com
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
new file mode 100644
index 0000000..7e7feaf
--- /dev/null
+++ b/apct-tests/perftests/OWNERS
@@ -0,0 +1,11 @@
+balejs@google.com
+carmenjackson@google.com
+cfijalkovich@google.com
+dualli@google.com
+edgararriaga@google.com
+jpakaravoor@google.com
+kevinjeon@google.com
+philipcuadra@google.com
+shombert@google.com
+timmurray@google.com
+wessam@google.com
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 65c28fb..84145be 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "AutofillPerfTests",
     srcs: ["src/**/*.java"],
@@ -20,7 +29,10 @@
         "androidx.test.rules",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
+        "compatibility-device-util-axt",
+        "collector-device-lib",
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
 }
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 1e3532b..57595a2 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -18,7 +18,8 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
-        <activity android:name="android.perftests.utils.PerfTestActivity">
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
           <intent-filter>
             <action android:name="com.android.perftests.core.PERFTEST" />
           </intent-filter>
@@ -27,7 +28,8 @@
         <service
             android:name="android.view.autofill.MyAutofillService"
             android:label="PERF AutofillService"
-            android:permission="android.permission.BIND_AUTOFILL_SERVICE" >
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
diff --git a/apct-tests/perftests/autofill/AndroidTest.xml b/apct-tests/perftests/autofill/AndroidTest.xml
index 29f9f94..eee7bdc 100644
--- a/apct-tests/perftests/autofill/AndroidTest.xml
+++ b/apct-tests/perftests/autofill/AndroidTest.xml
@@ -21,8 +21,40 @@
         <option name="test-file-name" value="AutofillPerfTests.apk" />
     </target_preparer>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.autofill" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
     </test>
 </configuration>
diff --git a/apct-tests/perftests/autofill/OWNERS b/apct-tests/perftests/autofill/OWNERS
new file mode 100644
index 0000000..c52751d
--- /dev/null
+++ b/apct-tests/perftests/autofill/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/autofill/OWNERS
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 48ce8ab..54e1860 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
@@ -11,46 +11,54 @@
  * 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
+ * limitations under the License.
  */
 
 package android.view.autofill;
 
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
 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.provider.Settings;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 
-import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
+import org.junit.rules.RuleChain;
 
 /**
  * Base class for all autofill tests.
  */
-@LargeTest
 public abstract class AbstractAutofillPerfTestCase {
 
+    private static final String TAG = "AbstractAutofillPerfTestCase";
+
     @ClassRule
     public static final SettingsStateKeeperRule mServiceSettingsKeeper =
             new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(),
                     Settings.Secure.AUTOFILL_SERVICE);
 
-    @Rule
-    public ActivityTestRule<PerfTestActivity> mActivityRule =
+    protected final AutofillTestWatcher mTestWatcher = MyAutofillService.getTestWatcher();
+    protected ActivityTestRule<PerfTestActivity> mActivityRule =
             new ActivityTestRule<>(PerfTestActivity.class);
+    protected PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    public final RuleChain mAllRules = RuleChain
+            .outerRule(mTestWatcher)
+            .around(mPerfStatusReporter)
+            .around(mActivityRule);
 
     private final int mLayoutId;
 
@@ -58,6 +66,27 @@
         mLayoutId = layoutId;
     }
 
+    @BeforeClass
+    public static void disableDefaultAugmentedService() {
+        Log.v(TAG, "@BeforeClass: disableDefaultAugmentedService()");
+        setDefaultAugmentedAutofillServiceEnabled(false);
+    }
+
+    @AfterClass
+    public static void enableDefaultAugmentedService() {
+        Log.v(TAG, "@AfterClass: enableDefaultAugmentedService()");
+        setDefaultAugmentedAutofillServiceEnabled(true);
+    }
+
+    /**
+     * Enables / disables the default augmented autofill service.
+     */
+    private static void setDefaultAugmentedAutofillServiceEnabled(boolean enabled) {
+        Log.d(TAG, "setDefaultAugmentedAutofillServiceEnabled(): " + enabled);
+        runShellCommand("cmd autofill set default-augmented-service-enabled 0 %s",
+                Boolean.toString(enabled));
+    }
+
     /**
      * Prepares the activity so that by the time the test is run it has reference to its fields.
      */
@@ -74,41 +103,8 @@
         });
     }
 
-    @Before
-    public void enableService() {
-        MyAutofillService.resetStaticState();
-        MyAutofillService.setEnabled(true);
-    }
-
-    @After
-    public void disableService() {
-        // Must disable service so calls are ignored in case of errors during the test case;
-        // otherwise, other tests will fail because these calls are made in the UI thread (as both
-        // the service, the tests, and the app run in the same process).
-        MyAutofillService.setEnabled(false);
-    }
-
     /**
      * Initializes the {@link PerfTestActivity} after it was launched.
      */
     protected abstract void onCreate(PerfTestActivity activity);
-
-    /**
-     * Uses the {@code settings} binary to set the autofill service.
-     */
-    protected void setService() {
-        SettingsHelper.syncSet(InstrumentationRegistry.getTargetContext(),
-                SettingsHelper.NAMESPACE_SECURE,
-                Settings.Secure.AUTOFILL_SERVICE,
-                MyAutofillService.COMPONENT_NAME);
-    }
-
-    /**
-     * Uses the {@code settings} binary to reset the autofill service.
-     */
-    protected void resetService() {
-        SettingsHelper.syncDelete(InstrumentationRegistry.getTargetContext(),
-                SettingsHelper.NAMESPACE_SECURE,
-                Settings.Secure.AUTOFILL_SERVICE);
-    }
 }
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java
new file mode 100644
index 0000000..0763729
--- /dev/null
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 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.view.autofill;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
+import android.service.autofill.FillContext;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Helper for common funcionalities.
+ */
+public class AutofillTestHelper {
+    private static final String TAG = "AutofillTestHelper";
+
+    /**
+     * Gets a node given its Android resource id, or {@code null} if not found.
+     */
+    public static ViewNode findNodeByResourceId(List<FillContext> contexts, String resourceId) {
+        for (FillContext context : contexts) {
+            ViewNode node = findNodeByResourceId(context.getStructure(), resourceId);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets a node if it matches the filter criteria for the given id.
+     */
+    private static ViewNode findNodeByResourceId(AssistStructure structure, String id) {
+        Log.v(TAG, "Parsing request for activity " + structure.getActivityComponent());
+        final int nodes = structure.getWindowNodeCount();
+        for (int i = 0; i < nodes; i++) {
+            final WindowNode windowNode = structure.getWindowNodeAt(i);
+            final ViewNode rootNode = windowNode.getRootViewNode();
+            final ViewNode node = findNodeByResourceId(rootNode, id);
+            if (node != null) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets a node if it matches the filter criteria for the given id.
+     */
+    private static ViewNode findNodeByResourceId(ViewNode node, String id) {
+        if (id.equals(node.getIdEntry())) {
+            return node;
+        }
+        final int childrenSize = node.getChildCount();
+        if (childrenSize > 0) {
+            for (int i = 0; i < childrenSize; i++) {
+                final ViewNode found = findNodeByResourceId(node.getChildAt(i), id);
+                if (found != null) {
+                    return found;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
new file mode 100644
index 0000000..f65067f
--- /dev/null
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 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.view.autofill;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import android.perftests.utils.SettingsHelper;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.Timeout;
+
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Custom {@link TestWatcher} that does the setup and reset tasks for the tests.
+ */
+final class AutofillTestWatcher extends TestWatcher {
+
+    private static final String TAG = "AutofillTestWatcher";
+    private static final long GENERIC_TIMEOUT_MS = 10_000;
+
+    private static ServiceWatcher sServiceWatcher;
+
+    private String mOriginalLogLevel;
+
+    @Override
+    protected void starting(Description description) {
+        super.starting(description);
+        final String testName = description.getDisplayName();
+        Log.i(TAG, "Starting " + testName);
+
+        prepareDevice();
+        enableVerboseLog();
+        // Prepare the service before each test.
+        // Disable the current AutofillService.
+        resetAutofillService();
+        // Set MyAutofillService status enable, it can start to accept the calls.
+        enableMyAutofillService();
+        setServiceWatcher();
+    }
+
+    @Override
+    protected void finished(Description description) {
+        super.finished(description);
+        final String testName = description.getDisplayName();
+        Log.i(TAG, "Finished " + testName);
+        restoreLogLevel();
+        // Set MyAutofillService status disable, so the calls are ignored.
+        disableMyAutofillService();
+        clearServiceWatcher();
+    }
+
+    void waitServiceConnect() throws InterruptedException {
+        if (sServiceWatcher != null) {
+            Log.d(TAG, "waitServiceConnect()");
+            sServiceWatcher.waitOnConnected();
+        }
+    }
+
+    /**
+     * Uses the {@code settings} binary to set the autofill service.
+     */
+    void setAutofillService() {
+        String serviceName = MyAutofillService.COMPONENT_NAME;
+        SettingsHelper.syncSet(InstrumentationRegistry.getTargetContext(),
+                SettingsHelper.NAMESPACE_SECURE,
+                Settings.Secure.AUTOFILL_SERVICE,
+                serviceName);
+        // Waits until the service is actually enabled.
+        Timeout timeout = new Timeout("CONNECTION_TIMEOUT", GENERIC_TIMEOUT_MS, 2F,
+                GENERIC_TIMEOUT_MS);
+        try {
+            timeout.run("Enabling Autofill service", () -> {
+                return isAutofillServiceEnabled(serviceName) ? serviceName : null;
+            });
+        } catch (Exception e) {
+            throw new AssertionError("Enabling Autofill service failed.");
+        }
+    }
+
+    /**
+     * Uses the {@code settings} binary to reset the autofill service.
+     */
+    void resetAutofillService() {
+        SettingsHelper.syncDelete(InstrumentationRegistry.getTargetContext(),
+                SettingsHelper.NAMESPACE_SECURE,
+                Settings.Secure.AUTOFILL_SERVICE);
+    }
+
+    /**
+     * Checks whether the given service is set as the autofill service for the default user.
+     */
+    private boolean isAutofillServiceEnabled(String serviceName) {
+        String actualName = SettingsHelper.get(SettingsHelper.NAMESPACE_SECURE,
+                Settings.Secure.AUTOFILL_SERVICE);
+        return serviceName.equals(actualName);
+    }
+
+    private void prepareDevice() {
+        // Unlock screen.
+        runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+        // Dismiss keyguard, in case it's set as "Swipe to unlock".
+        runShellCommand("wm dismiss-keyguard");
+
+        // Collapse notifications.
+        runShellCommand("cmd statusbar collapse");
+    }
+
+    private void enableMyAutofillService() {
+        MyAutofillService.resetStaticState();
+        MyAutofillService.setEnabled(true);
+    }
+
+    private void disableMyAutofillService() {
+        // Must disable service so calls are ignored in case of errors during the test case;
+        // otherwise, other tests will fail because these calls are made in the UI thread (as both
+        // the service, the tests, and the app run in the same process).
+        MyAutofillService.setEnabled(false);
+    }
+
+    private void enableVerboseLog() {
+        mOriginalLogLevel = runShellCommand("cmd autofill get log_level");
+        Log.d(TAG, "enableVerboseLog(), mOriginalLogLevel=" + mOriginalLogLevel);
+        if (!mOriginalLogLevel.equals("verbose")) {
+            runShellCommand("cmd autofill set log_level verbose");
+        }
+    }
+
+    private void restoreLogLevel() {
+        Log.d(TAG, "restoreLogLevel to " + mOriginalLogLevel);
+        if (!mOriginalLogLevel.equals("verbose")) {
+            runShellCommand("cmd autofill set log_level %s", mOriginalLogLevel);
+        }
+    }
+
+    private static void setServiceWatcher() {
+        if (sServiceWatcher == null) {
+            sServiceWatcher = new ServiceWatcher();
+        }
+    }
+
+    private static void clearServiceWatcher() {
+        if (sServiceWatcher != null) {
+            sServiceWatcher = null;
+        }
+    }
+
+    public static final class ServiceWatcher {
+        private final CountDownLatch mConnected = new CountDownLatch(1);
+
+        public static void onConnected() {
+            Log.i(TAG, "onConnected:  sServiceWatcher=" + sServiceWatcher);
+
+            sServiceWatcher.mConnected.countDown();
+        }
+
+        @NonNull
+        public void waitOnConnected() throws InterruptedException {
+            await(mConnected, "not connected");
+        }
+
+        private void await(@NonNull CountDownLatch latch, @NonNull String fmt,
+                @Nullable Object... args)
+                throws InterruptedException {
+            final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            if (!called) {
+                throw new IllegalStateException(String.format(fmt, args)
+                        + " in " + GENERIC_TIMEOUT_MS + "ms");
+            }
+        }
+    }
+}
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 fb5ea80..a5d1e00 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -11,7 +11,7 @@
  * 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
+ * limitations under the License.
  */
 
 package android.view.autofill;
@@ -24,12 +24,18 @@
 import android.view.View;
 import android.widget.EditText;
 
+import androidx.test.filters.LargeTest;
+
 import com.android.perftests.autofill.R;
 
 import org.junit.Test;
 
+@LargeTest
 public class LoginTest extends AbstractAutofillPerfTestCase {
 
+    public static final String ID_USERNAME = "username";
+    public static final String ID_PASSWORD = "password";
+
     private EditText mUsername;
     private EditText mPassword;
     private AutofillManager mAfm;
@@ -51,15 +57,15 @@
      */
     @Test
     public void testFocus_noService() throws Throwable {
-        resetService();
+        mTestWatcher.resetAutofillService();
 
-        mActivityRule.runOnUiThread(() -> {
-            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-            while (state.keepRunning()) {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mActivityRule.runOnUiThread(() -> {
                 mUsername.requestFocus();
                 mPassword.requestFocus();
-            }
-        });
+            });
+        }
     }
 
     /**
@@ -69,22 +75,23 @@
     @Test
     public void testFocus_serviceDoesNotAutofill() throws Throwable {
         MyAutofillService.newCannedResponse().reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Must first focus in a field to trigger autofill and wait for service response
         // outside the loop
         mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+        mTestWatcher.waitServiceConnect();
         MyAutofillService.getLastFillRequest();
         // Then focus on password so loop start with focus away from username
         mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
 
-        mActivityRule.runOnUiThread(() -> {
-            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-            while (state.keepRunning()) {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mActivityRule.runOnUiThread(() -> {
                 mUsername.requestFocus();
                 mPassword.requestFocus();
-            }
-        });
+            });
+        }
     }
 
     /**
@@ -93,10 +100,10 @@
     @Test
     public void testFocus_autofillBothFields() throws Throwable {
         MyAutofillService.newCannedResponse()
-                .setUsername(mUsername.getAutofillId(), "user")
-                .setPassword(mPassword.getAutofillId(), "pass")
+                .setUsername(ID_USERNAME, "user")
+                .setPassword(ID_PASSWORD, "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Callback is used to slow down the calls made to the autofill server so the
         // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
@@ -106,6 +113,7 @@
 
         // Must first trigger autofill and wait for service response outside the loop
         mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+        mTestWatcher.waitServiceConnect();
         MyAutofillService.getLastFillRequest();
         callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
 
@@ -146,10 +154,10 @@
     public void testFocus_autofillUsernameOnly() throws Throwable {
         // Must set ignored ids so focus on password does not trigger new requests
         MyAutofillService.newCannedResponse()
-                .setUsername(mUsername.getAutofillId(), "user")
-                .setIgnored(mPassword.getAutofillId())
+                .setUsername(ID_USERNAME, "user")
+                .setIgnored(ID_PASSWORD)
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Callback is used to slow down the calls made to the autofill server so the
         // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
@@ -159,6 +167,7 @@
 
         // Must first trigger autofill and wait for service response outside the loop
         mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+        mTestWatcher.waitServiceConnect();
         MyAutofillService.getLastFillRequest();
         callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
 
@@ -193,7 +202,7 @@
      */
     @Test
     public void testChange_noService() throws Throwable {
-        resetService();
+        mTestWatcher.resetAutofillService();
 
         changeTest(false);
     }
@@ -205,7 +214,7 @@
     @Test
     public void testChange_serviceDoesNotAutofill() throws Throwable {
         MyAutofillService.newCannedResponse().reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -216,10 +225,10 @@
     @Test
     public void testChange_autofillBothFields() throws Throwable {
         MyAutofillService.newCannedResponse()
-                .setUsername(mUsername.getAutofillId(), "user")
-                .setPassword(mPassword.getAutofillId(), "pass")
+                .setUsername(ID_USERNAME, "user")
+                .setPassword(ID_PASSWORD, "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -231,10 +240,10 @@
     public void testChange_autofillUsernameOnly() throws Throwable {
         // Must set ignored ids so focus on password does not trigger new requests
         MyAutofillService.newCannedResponse()
-                .setUsername(mUsername.getAutofillId(), "user")
-                .setIgnored(mPassword.getAutofillId())
+                .setUsername(ID_USERNAME, "user")
+                .setIgnored(ID_PASSWORD)
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -244,27 +253,27 @@
         // outside the loop
         mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
         if (waitForService) {
+            mTestWatcher.waitServiceConnect();
             MyAutofillService.getLastFillRequest();
         }
-        mActivityRule.runOnUiThread(() -> {
-
-            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-            while (state.keepRunning()) {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mActivityRule.runOnUiThread(() -> {
                 mUsername.setText("");
                 mUsername.setText("a");
                 mPassword.setText("");
                 mPassword.setText("x");
-            }
-        });
+            });
+        }
     }
 
     @Test
     public void testCallbacks() throws Throwable {
         MyAutofillService.newCannedResponse()
-                .setUsername(mUsername.getAutofillId(), "user")
-                .setPassword(mPassword.getAutofillId(), "pass")
+                .setUsername(ID_USERNAME, "user")
+                .setPassword(ID_PASSWORD, "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         MyAutofillCallback callback = new MyAutofillCallback();
         mAfm.registerCallback(callback);
@@ -272,6 +281,7 @@
         // Must first focus in a field to trigger autofill and wait for service response
         // outside the loop
         mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+        mTestWatcher.waitServiceConnect();
         MyAutofillService.getLastFillRequest();
         callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
 
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
index 7060233..5db6597 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
@@ -11,10 +11,11 @@
  * 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
+ * limitations under the License.
  */
 package android.view.autofill;
 
+import android.app.assist.AssistStructure.ViewNode;
 import android.os.CancellationSignal;
 import android.service.autofill.AutofillService;
 import android.service.autofill.Dataset;
@@ -28,12 +29,9 @@
 import android.widget.RemoteViews;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.perftests.autofill.R;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -44,7 +42,7 @@
 public class MyAutofillService extends AutofillService {
 
     private static final String TAG = "MyAutofillService";
-    private static final int TIMEOUT_MS = 5000;
+    private static final int TIMEOUT_MS = 5_000;
 
     private static final String PACKAGE_NAME = "com.android.perftests.autofill";
     static final String COMPONENT_NAME = PACKAGE_NAME + "/android.view.autofill.MyAutofillService";
@@ -56,6 +54,14 @@
     private static boolean sEnabled;
 
     /**
+     * Returns the TestWatcher that was used for the testing.
+     */
+    @NonNull
+    public static AutofillTestWatcher getTestWatcher() {
+        return new AutofillTestWatcher();
+    }
+
+    /**
      * Resets the static state associated with the service.
      */
     static void resetStaticState() {
@@ -93,6 +99,11 @@
     }
 
     @Override
+    public void onConnected() {
+        AutofillTestWatcher.ServiceWatcher.onConnected();
+    }
+
+    @Override
     public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal,
             FillCallback callback) {
         try {
@@ -120,20 +131,27 @@
         boolean hasData = false;
         if (response.mUsername != null) {
             hasData = true;
-            dataset.setValue(response.mUsername.first,
-                    AutofillValue.forText(response.mUsername.second));
+            AutofillId autofillId = getAutofillIdByResourceId(request, response.mUsername.first);
+            AutofillValue value = AutofillValue.forText(response.mUsername.second);
+            dataset.setValue(autofillId, value, newDatasetPresentation("dataset"));
         }
         if (response.mPassword != null) {
             hasData = true;
-            dataset.setValue(response.mPassword.first,
-                    AutofillValue.forText(response.mPassword.second));
+            AutofillId autofillId = getAutofillIdByResourceId(request, response.mPassword.first);
+            AutofillValue value = AutofillValue.forText(response.mPassword.second);
+            dataset.setValue(autofillId, value, newDatasetPresentation("dataset"));
         }
         if (hasData) {
             FillResponse.Builder fillResponse = new FillResponse.Builder();
             if (response.mIgnoredIds != null) {
-                fillResponse.setIgnoredIds(response.mIgnoredIds);
+                int length = response.mIgnoredIds.length;
+                AutofillId[] requiredIds = new AutofillId[length];
+                for (int i = 0; i < length; i++) {
+                    String resourceId = response.mIgnoredIds[i];
+                    requiredIds[i] = getAutofillIdByResourceId(request, resourceId);
+                }
+                fillResponse.setIgnoredIds(requiredIds);
             }
-
             callback.onSuccess(fillResponse.addDataset(dataset.build()).build());
         } else {
             callback.onSuccess(null);
@@ -143,6 +161,16 @@
         }
     }
 
+    private AutofillId getAutofillIdByResourceId(FillRequest request, String resourceId)
+            throws Exception {
+        ViewNode node = AutofillTestHelper.findNodeByResourceId(request.getFillContexts(),
+                resourceId);
+        if (node == null) {
+            throw new AssertionError("No node with resource id " + resourceId);
+        }
+        return node.getAutofillId();
+    }
+
     @Override
     public void onSaveRequest(SaveRequest request, SaveCallback callback) {
         // No current test should have triggered it...
@@ -151,9 +179,9 @@
     }
 
     static final class CannedResponse {
-        private final Pair<AutofillId, String> mUsername;
-        private final Pair<AutofillId, String> mPassword;
-        private final AutofillId[] mIgnoredIds;
+        private final Pair<String, String> mUsername;
+        private final Pair<String, String> mPassword;
+        private final String[] mIgnoredIds;
 
         private CannedResponse(@NonNull Builder builder) {
             mUsername = builder.mUsername;
@@ -162,24 +190,24 @@
         }
 
         static class Builder {
-            private Pair<AutofillId, String> mUsername;
-            private Pair<AutofillId, String> mPassword;
-            private AutofillId[] mIgnoredIds;
+            private Pair<String, String> mUsername;
+            private Pair<String, String> mPassword;
+            private String[] mIgnoredIds;
 
             @NonNull
-            Builder setUsername(@NonNull AutofillId id, @NonNull String value) {
+            Builder setUsername(@NonNull String id, @NonNull String value) {
                 mUsername = new Pair<>(id, value);
                 return this;
             }
 
             @NonNull
-            Builder setPassword(@NonNull AutofillId id, @NonNull String value) {
+            Builder setPassword(@NonNull String id, @NonNull String value) {
                 mPassword = new Pair<>(id, value);
                 return this;
             }
 
             @NonNull
-            Builder setIgnored(AutofillId... ids) {
+            Builder setIgnored(String... ids) {
                 mIgnoredIds = ids;
                 return this;
             }
diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp
index be5072c..25c4250 100644
--- a/apct-tests/perftests/blobstore/Android.bp
+++ b/apct-tests/perftests/blobstore/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
   name: "BlobStorePerfTests",
   srcs: ["src/**/*.java"],
@@ -21,8 +30,9 @@
     "androidx.annotation_annotation",
     "apct-perftests-utils",
     "ub-uiautomator",
+    "collector-device-lib-platform",
   ],
   platform_apis: true,
   test_suites: ["device-tests"],
   certificate: "platform",
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/blobstore/AndroidTest.xml b/apct-tests/perftests/blobstore/AndroidTest.xml
index 19456c6..58761d0 100644
--- a/apct-tests/perftests/blobstore/AndroidTest.xml
+++ b/apct-tests/perftests/blobstore/AndroidTest.xml
@@ -24,5 +24,22 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.blob" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- TODO: Add PerfettoListener to automatically capture perfetto traces for each test-->
+        <!-- Listener related args for collecting the traces and waiting for the device
+             to stabilize. -->
+        <option name="device-listeners"
+                value="android.device.collectors.ProcLoadListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default
+             listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before
+             starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
     </test>
 </configuration>
\ No newline at end of file
diff --git a/apct-tests/perftests/blobstore/OWNERS b/apct-tests/perftests/blobstore/OWNERS
new file mode 100644
index 0000000..65bb6b8
--- /dev/null
+++ b/apct-tests/perftests/blobstore/OWNERS
@@ -0,0 +1 @@
+include /apex/blobstore/OWNERS
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 23f025b..5a04ba3 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -27,7 +27,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.utils.blob.DummyBlobData;
+import com.android.utils.blob.FakeBlobData;
 
 import org.junit.After;
 import org.junit.Before;
@@ -96,7 +96,7 @@
         mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
         try {
             final List<Long> durations = new ArrayList<>();
-            final DummyBlobData blobData = prepareDataBlob(fileSizeInMb);
+            final FakeBlobData blobData = prepareDataBlob(fileSizeInMb);
             final TraceMarkParser parser = new TraceMarkParser(
                     line -> line.name.startsWith(ATRACE_COMPUTE_DIGEST_PREFIX));
             while (mState.keepRunning(durations)) {
@@ -120,15 +120,15 @@
         });
     }
 
-    private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
-        final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+    private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
+        final FakeBlobData blobData = new FakeBlobData.Builder(mContext)
                 .setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
                 .build();
         blobData.prepare();
         return blobData;
     }
 
-    private void commitBlob(DummyBlobData blobData) throws Exception {
+    private void commitBlob(FakeBlobData blobData) throws Exception {
         final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
         try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
             blobData.writeToSession(session);
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp
new file mode 100644
index 0000000..638403d
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "ContentCapturePerfTests",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.annotation_annotation",
+        "apct-perftests-utils",
+        "collector-device-lib",
+        "compatibility-device-util-axt",
+    ],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
+}
diff --git a/apct-tests/perftests/contentcapture/AndroidManifest.xml b/apct-tests/perftests/contentcapture/AndroidManifest.xml
new file mode 100644
index 0000000..80957c7
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.contentcapture">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.view.contentcapture.CustomTestActivity"
+                android:exported="true">
+        </activity>
+
+        <service
+            android:name="android.view.contentcapture.MyContentCaptureService"
+            android:label="PERF ContentCaptureService"
+            android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.service.contentcapture.ContentCaptureService" />
+            </intent-filter>
+        </service>
+
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.perftests.contentcapture" />
+</manifest>
diff --git a/apct-tests/perftests/contentcapture/AndroidTest.xml b/apct-tests/perftests/contentcapture/AndroidTest.xml
new file mode 100644
index 0000000..d8e0a17
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/AndroidTest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs ContentCapturePerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="ContentCapturePerfTests.apk" />
+    </target_preparer>
+
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.perftests.contentcapture" />
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+    </test>
+</configuration>
diff --git a/apct-tests/perftests/contentcapture/OWNERS b/apct-tests/perftests/contentcapture/OWNERS
new file mode 100644
index 0000000..a28e00a
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/contentcapture/OWNERS
diff --git a/apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml b/apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml
new file mode 100644
index 0000000..ca1a11a
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools"
+              android:id="@+id/root_view"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:focusable="true"
+              android:focusableInTouchMode="true"
+              android:orientation="vertical" >
+</LinearLayout>
diff --git a/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml b/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml
new file mode 100644
index 0000000..9bab32c
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:tools="http://schemas.android.com/tools"
+              android:id="@+id/root_view"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:focusable="true"
+              android:focusableInTouchMode="true"
+              android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/username_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Username" />
+
+    <EditText
+        android:id="@+id/username"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:id="@+id/password_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Password" />
+
+    <EditText
+        android:id="@+id/password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:inputType="textPassword" />
+
+</LinearLayout>
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
new file mode 100644
index 0000000..9b853fe
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2020 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.view.contentcapture;
+
+import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_CUSTOM_VIEWS;
+import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_LAYOUT_ID;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import android.app.Application;
+import android.content.ContentCaptureOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.perftests.utils.PerfStatusReporter;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher;
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.perftests.contentcapture.R;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+/**
+ * Base class for all content capture tests.
+ */
+public abstract class AbstractContentCapturePerfTestCase {
+
+    private static final String TAG = AbstractContentCapturePerfTestCase.class.getSimpleName();
+    private static final long GENERIC_TIMEOUT_MS = 10_000;
+
+    private static int sOriginalStayOnWhilePluggedIn;
+    private static Context sContext = getInstrumentation().getTargetContext();
+
+    protected ActivitiesWatcher mActivitiesWatcher;
+
+    private MyContentCaptureService.ServiceWatcher mServiceWatcher;
+
+    @Rule
+    public ActivityTestRule<CustomTestActivity> mActivityRule =
+            new ActivityTestRule<>(CustomTestActivity.class, false, false);
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Rule
+    public TestRule mServiceDisablerRule = (base, description) -> {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    base.evaluate();
+                } finally {
+                    Log.v(TAG, "@mServiceDisablerRule: safelyDisableService()");
+                    safelyDisableService();
+                }
+            }
+        };
+    };
+
+    private void safelyDisableService() {
+        try {
+            resetService();
+            MyContentCaptureService.resetStaticState();
+
+            if (mServiceWatcher != null) {
+                mServiceWatcher.waitOnDestroy();
+            }
+        } catch (Throwable t) {
+            Log.e(TAG, "error disabling service", t);
+        }
+    }
+
+    /**
+     * Sets the content capture service.
+     */
+    private static void setService(@NonNull String service) {
+        final int userId = getCurrentUserId();
+        Log.d(TAG, "Setting service for user " + userId + " to " + service);
+        // TODO(b/123540602): use @TestingAPI to get max duration constant
+        runShellCommand("cmd content_capture set temporary-service %d %s 119000", userId, service);
+    }
+
+    /**
+     * Resets the content capture service.
+     */
+    private static void resetService() {
+        final int userId = getCurrentUserId();
+        Log.d(TAG, "Resetting back user " + userId + " to default service");
+        runShellCommand("cmd content_capture set temporary-service %d", userId);
+    }
+
+    private static int getCurrentUserId() {
+        return UserHandle.myUserId();
+    }
+
+    @BeforeClass
+    public static void setStayAwake() {
+        Log.v(TAG, "@BeforeClass: setStayAwake()");
+        // Some test cases will restart the activity, and stay awake is necessary to ensure that
+        // the test will not screen off during the test.
+        // Keeping the activity screen on is not enough, screen off may occur between the activity
+        // finished and the next start
+        final int stayOnWhilePluggedIn = Settings.Global.getInt(sContext.getContentResolver(),
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+        sOriginalStayOnWhilePluggedIn = -1;
+        if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
+            sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
+            // Keep the device awake during testing.
+            setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
+        }
+    }
+
+    @AfterClass
+    public static void resetStayAwake() {
+        Log.v(TAG, "@AfterClass: resetStayAwake()");
+        if (sOriginalStayOnWhilePluggedIn != -1) {
+            setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
+        }
+    }
+
+    private static void setStayOnWhilePluggedIn(int value) {
+        runShellCommand(String.format("settings put global %s %d",
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value));
+    }
+
+    @BeforeClass
+    public static void setAllowSelf() {
+        final ContentCaptureOptions options = new ContentCaptureOptions(null);
+        Log.v(TAG, "@BeforeClass: setAllowSelf(): options=" + options);
+        sContext.getApplicationContext().setContentCaptureOptions(options);
+    }
+
+    @AfterClass
+    public static void unsetAllowSelf() {
+        Log.v(TAG, "@AfterClass: unsetAllowSelf()");
+        clearOptions();
+    }
+
+    protected static void clearOptions() {
+        sContext.getApplicationContext().setContentCaptureOptions(null);
+    }
+
+    @BeforeClass
+    public static void disableDefaultService() {
+        Log.v(TAG, "@BeforeClass: disableDefaultService()");
+        setDefaultServiceEnabled(false);
+    }
+
+    @AfterClass
+    public static void enableDefaultService() {
+        Log.v(TAG, "@AfterClass: enableDefaultService()");
+        setDefaultServiceEnabled(true);
+    }
+
+    /**
+     * Enables / disables the default service.
+     */
+    private static void setDefaultServiceEnabled(boolean enabled) {
+        final int userId = getCurrentUserId();
+        Log.d(TAG, "setDefaultServiceEnabled(user=" + userId + ", enabled= " + enabled + ")");
+        runShellCommand("cmd content_capture set default-service-enabled %d %s", userId,
+                Boolean.toString(enabled));
+    }
+
+    @Before
+    public void prepareDevice() throws Exception {
+        Log.v(TAG, "@Before: prepareDevice()");
+
+        // Unlock screen.
+        runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+        // Dismiss keyguard, in case it's set as "Swipe to unlock".
+        runShellCommand("wm dismiss-keyguard");
+
+        // Collapse notifications.
+        runShellCommand("cmd statusbar collapse");
+    }
+
+    @Before
+    public void registerLifecycleCallback() {
+        Log.v(TAG, "@Before: Registering lifecycle callback");
+        final Application app = (Application) sContext.getApplicationContext();
+        mActivitiesWatcher = new ActivitiesWatcher(GENERIC_TIMEOUT_MS);
+        app.registerActivityLifecycleCallbacks(mActivitiesWatcher);
+    }
+
+    @After
+    public void unregisterLifecycleCallback() {
+        Log.d(TAG, "@After: Unregistering lifecycle callback: " + mActivitiesWatcher);
+        if (mActivitiesWatcher != null) {
+            final Application app = (Application) sContext.getApplicationContext();
+            app.unregisterActivityLifecycleCallbacks(mActivitiesWatcher);
+        }
+    }
+
+    /**
+     * Sets {@link MyContentCaptureService} as the service for the current user and waits until
+     * its created, then add the perf test package into allow list.
+     */
+    public MyContentCaptureService enableService() throws InterruptedException {
+        if (mServiceWatcher != null) {
+            throw new IllegalStateException("There Can Be Only One!");
+        }
+
+        mServiceWatcher = MyContentCaptureService.setServiceWatcher();
+        setService(MyContentCaptureService.SERVICE_NAME);
+        mServiceWatcher.setAllowSelf();
+        return mServiceWatcher.waitOnCreate();
+    }
+
+    @NonNull
+    protected ActivityWatcher startWatcher() {
+        return mActivitiesWatcher.watch(CustomTestActivity.class);
+    }
+
+    /**
+     * Launch test activity with default login layout
+     */
+    protected CustomTestActivity launchActivity() {
+        return launchActivity(R.layout.test_login_activity, 0);
+    }
+
+    /**
+     * Launch test activity with give layout and parameter
+     */
+    protected CustomTestActivity launchActivity(int layoutId, int numViews) {
+        final Intent intent = new Intent(sContext, CustomTestActivity.class);
+        intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
+        intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
+        return mActivityRule.launchActivity(intent);
+    }
+
+    protected void finishActivity() {
+        try {
+            mActivityRule.finishActivity();
+        } catch (IllegalStateException e) {
+            // no op
+        }
+    }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java
new file mode 100644
index 0000000..e509837
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.contentcapture;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.perftests.contentcapture.R;
+
+/**
+ * A simple activity used for testing, e.g. performance of activity switching, or as a base
+ * container of testing view.
+ */
+public class CustomTestActivity extends Activity {
+    public static final String INTENT_EXTRA_LAYOUT_ID = "layout_id";
+    public static final String INTENT_EXTRA_CUSTOM_VIEWS = "custom_view_number";
+    public static final int MAX_VIEWS = 500;
+    private static final int CUSTOM_CONTAINER_LAYOUT_ID = R.layout.test_container_activity;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (getIntent().hasExtra(INTENT_EXTRA_LAYOUT_ID)) {
+            final int layoutId = getIntent().getIntExtra(INTENT_EXTRA_LAYOUT_ID,
+                    /* defaultValue= */0);
+            setContentView(layoutId);
+            if (layoutId == CUSTOM_CONTAINER_LAYOUT_ID) {
+                createCustomViews(findViewById(R.id.root_view),
+                        getIntent().getIntExtra(INTENT_EXTRA_CUSTOM_VIEWS, MAX_VIEWS));
+            }
+        }
+    }
+
+    private void createCustomViews(LinearLayout root, int number) {
+        LinearLayout horizontalLayout = null;
+        for (int i = 0; i < number; i++) {
+            final int j = i % 8;
+            if (horizontalLayout != null && j == 0) {
+                root.addView(horizontalLayout);
+                horizontalLayout = null;
+            }
+            if (horizontalLayout == null) {
+                horizontalLayout = createHorizontalLayout();
+            }
+            horizontalLayout.addView(createItem(null, i));
+        }
+        if (horizontalLayout != null) {
+            root.addView(horizontalLayout);
+        }
+    }
+
+    private LinearLayout createHorizontalLayout() {
+        final LinearLayout layout = new LinearLayout(getApplicationContext());
+        layout.setOrientation(LinearLayout.HORIZONTAL);
+        return layout;
+    }
+
+    private LinearLayout createItem(Drawable drawable, int index) {
+        final LinearLayout group = new LinearLayout(getApplicationContext());
+        group.setOrientation(LinearLayout.VERTICAL);
+        group.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT, /* weight= */ 1.0f));
+
+        final TextView text = new TextView(this);
+        text.setText("i = " + index);
+        group.addView(text);
+
+        return group;
+    }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
new file mode 100644
index 0000000..7257509
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 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.view.contentcapture;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.CREATED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+
+import android.perftests.utils.BenchmarkState;
+import android.view.View;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.perftests.contentcapture.R;
+
+import org.junit.Test;
+
+@LargeTest
+public class LoginTest extends AbstractContentCapturePerfTestCase {
+
+    @Test
+    public void testLaunchActivity() throws Throwable {
+        enableService();
+
+        testActivityLaunchTime(R.layout.test_login_activity, 0);
+    }
+
+    @Test
+    public void testLaunchActivity_contain100Views() throws Throwable {
+        enableService();
+
+        testActivityLaunchTime(R.layout.test_container_activity, 100);
+    }
+
+    @Test
+    public void testLaunchActivity_contain300Views() throws Throwable {
+        enableService();
+
+        testActivityLaunchTime(R.layout.test_container_activity, 300);
+    }
+
+    @Test
+    public void testLaunchActivity_contain500Views() throws Throwable {
+        enableService();
+
+        testActivityLaunchTime(R.layout.test_container_activity, 500);
+    }
+
+    @Test
+    public void testLaunchActivity_noService() throws Throwable {
+        testActivityLaunchTime(R.layout.test_login_activity, 0);
+    }
+
+    @Test
+    public void testLaunchActivity_noService_contain100Views() throws Throwable {
+        testActivityLaunchTime(R.layout.test_container_activity, 100);
+    }
+
+    @Test
+    public void testLaunchActivity_noService_contain300Views() throws Throwable {
+        testActivityLaunchTime(R.layout.test_container_activity, 300);
+    }
+
+    @Test
+    public void testLaunchActivity_noService_contain500Views() throws Throwable {
+        testActivityLaunchTime(R.layout.test_container_activity, 500);
+    }
+
+    private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
+        final ActivityWatcher watcher = startWatcher();
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            launchActivity(layoutId, numViews);
+
+            // Ignore the time to finish the activity
+            state.pauseTiming();
+            watcher.waitFor(CREATED);
+            finishActivity();
+            watcher.waitFor(DESTROYED);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void testOnVisibilityAggregated_visibleChanged() throws Throwable {
+        enableService();
+        final CustomTestActivity activity = launchActivity();
+        final View root = activity.getWindow().getDecorView();
+        final View username = root.findViewById(R.id.username);
+
+        testOnVisibilityAggregated(username);
+    }
+
+    @Test
+    public void testOnVisibilityAggregated_visibleChanged_noService() throws Throwable {
+        final CustomTestActivity activity = launchActivity();
+        final View root = activity.getWindow().getDecorView();
+        final View username = root.findViewById(R.id.username);
+
+        testOnVisibilityAggregated(username);
+    }
+
+    @Test
+    public void testOnVisibilityAggregated_visibleChanged_noOptions() throws Throwable {
+        enableService();
+        clearOptions();
+        final CustomTestActivity activity = launchActivity();
+        final View root = activity.getWindow().getDecorView();
+        final View username = root.findViewById(R.id.username);
+
+        testOnVisibilityAggregated(username);
+    }
+
+    @Test
+    public void testOnVisibilityAggregated_visibleChanged_notImportant() throws Throwable {
+        enableService();
+        final CustomTestActivity activity = launchActivity();
+        final View root = activity.getWindow().getDecorView();
+        final View username = root.findViewById(R.id.username);
+        username.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO);
+
+        testOnVisibilityAggregated(username);
+    }
+
+    private void testOnVisibilityAggregated(View view) throws Throwable {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            // Only count the time of onVisibilityAggregated()
+            state.pauseTiming();
+            mActivityRule.runOnUiThread(() -> {
+                state.resumeTiming();
+                view.onVisibilityAggregated(false);
+                state.pauseTiming();
+            });
+            mActivityRule.runOnUiThread(() -> {
+                state.resumeTiming();
+                view.onVisibilityAggregated(true);
+                state.pauseTiming();
+            });
+            state.resumeTiming();
+        }
+    }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
new file mode 100644
index 0000000..d07ed37
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2020 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.view.contentcapture;
+
+import android.content.ComponentName;
+import android.service.contentcapture.ActivityEvent;
+import android.service.contentcapture.ContentCaptureService;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MyContentCaptureService extends ContentCaptureService {
+
+    private static final String TAG = MyContentCaptureService.class.getSimpleName();
+    private static final String MY_PACKAGE = "com.android.perftests.contentcapture";
+    public static final String SERVICE_NAME = MY_PACKAGE + "/"
+            + MyContentCaptureService.class.getName();
+
+    private static ServiceWatcher sServiceWatcher;
+
+    @NonNull
+    public static ServiceWatcher setServiceWatcher() {
+        if (sServiceWatcher != null) {
+            throw new IllegalStateException("There Can Be Only One!");
+        }
+        sServiceWatcher = new ServiceWatcher();
+        return sServiceWatcher;
+    }
+
+    public static void resetStaticState() {
+        sServiceWatcher = null;
+    }
+
+    private static void clearServiceWatcher() {
+        final ServiceWatcher sw = sServiceWatcher;
+        if (sw != null) {
+            if (sw.mReadyToClear) {
+                sw.mService = null;
+                sServiceWatcher = null;
+            } else {
+                sw.mReadyToClear = true;
+            }
+        }
+    }
+
+    @Override
+    public void onConnected() {
+        Log.i(TAG, "onConnected: sServiceWatcher=" + sServiceWatcher);
+
+        if (sServiceWatcher == null) {
+            Log.e(TAG, "onConnected() without a watcher");
+            return;
+        }
+
+        if (!sServiceWatcher.mReadyToClear && sServiceWatcher.mService != null) {
+            Log.e(TAG, "onConnected(): already created: " + sServiceWatcher);
+            return;
+        }
+
+        sServiceWatcher.mService = this;
+        sServiceWatcher.mCreated.countDown();
+        sServiceWatcher.mReadyToClear = false;
+    }
+
+    @Override
+    public void onDisconnected() {
+        Log.i(TAG, "onDisconnected: sServiceWatcher=" + sServiceWatcher);
+
+        if (sServiceWatcher == null) {
+            Log.e(TAG, "onDisconnected() without a watcher");
+            return;
+        }
+        if (sServiceWatcher.mService == null) {
+            Log.e(TAG, "onDisconnected(): no service on " + sServiceWatcher);
+            return;
+        }
+
+        sServiceWatcher.mDestroyed.countDown();
+        clearServiceWatcher();
+    }
+
+    @Override
+    public void onCreateContentCaptureSession(ContentCaptureContext context,
+            ContentCaptureSessionId sessionId) {
+        Log.i(TAG, "onCreateContentCaptureSession(ctx=" + context + ", session=" + sessionId);
+    }
+
+    @Override
+    public void onDestroyContentCaptureSession(ContentCaptureSessionId sessionId) {
+        Log.i(TAG, "onDestroyContentCaptureSession(session=" + sessionId + ")");
+    }
+
+    @Override
+    public void onContentCaptureEvent(ContentCaptureSessionId sessionId,
+            ContentCaptureEvent event) {
+        Log.i(TAG, "onContentCaptureEventsRequest(session=" + sessionId + "): " + event);
+    }
+
+    @Override
+    public void onActivityEvent(ActivityEvent event) {
+        Log.i(TAG, "onActivityEvent(): " + event);
+    }
+
+    public static final class ServiceWatcher {
+
+        private static final long GENERIC_TIMEOUT_MS = 10_000;
+        private final CountDownLatch mCreated = new CountDownLatch(1);
+        private final CountDownLatch mDestroyed = new CountDownLatch(1);
+        private boolean mReadyToClear = true;
+        private Pair<Set<String>, Set<ComponentName>> mAllowList;
+
+        private MyContentCaptureService mService;
+
+        @NonNull
+        public MyContentCaptureService waitOnCreate() throws InterruptedException {
+            await(mCreated, "not created");
+
+            if (mService == null) {
+                throw new IllegalStateException("not created");
+            }
+
+            if (mAllowList != null) {
+                Log.d(TAG, "Allow after created: " + mAllowList);
+                mService.setContentCaptureWhitelist(mAllowList.first, mAllowList.second);
+            }
+
+            return mService;
+        }
+
+        public void waitOnDestroy() throws InterruptedException {
+            await(mDestroyed, "not destroyed");
+        }
+
+        /**
+         * Allow just this package.
+         */
+        public void setAllowSelf() {
+            final ArraySet<String> pkgs = new ArraySet<>(1);
+            pkgs.add(MY_PACKAGE);
+            mAllowList = new Pair<>(pkgs, null);
+        }
+
+        @Override
+        public String toString() {
+            return "mService: " + mService + " created: " + (mCreated.getCount() == 0)
+                    + " destroyed: " + (mDestroyed.getCount() == 0);
+        }
+
+        /**
+         * Awaits for a latch to be counted down.
+         */
+        private static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
+                @Nullable Object... args)
+                throws InterruptedException {
+            final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            if (!called) {
+                throw new IllegalStateException(String.format(fmt, args)
+                        + " in " + GENERIC_TIMEOUT_MS + "ms");
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index 984893a..2182f0b 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -1,3 +1,28 @@
+//
+// Copyright (C) 2020 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "CorePerfTests",
 
@@ -12,23 +37,25 @@
         "androidx.appcompat_appcompat",
         "androidx.test.rules",
         "androidx.annotation_annotation",
+        "androidx.benchmark_benchmark-common",
+        "androidx.benchmark_benchmark-junit4",
         "apct-perftests-overlay-apps",
         "apct-perftests-resources-manager-apps",
         "apct-perftests-utils",
+        "collector-device-lib",
         "guava",
     ],
 
     libs: ["android.test.base"],
 
+    java_resources: [ ":GoogleFontDancingScript", ],
+
+    data: [":perfetto_artifacts"],
+
     platform_apis: true,
 
     jni_libs: ["libperftestscore_jni"],
 
-    // Use google-fonts/dancing-script for the performance metrics
-    // ANDROIDMK TRANSLATION ERROR: Only $(LOCAL_PATH)/.. values are allowed
-    // LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script
-
     test_suites: ["device-tests"],
     certificate: "platform",
-
 }
diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml
index 290f178..e0c11cf 100644
--- a/apct-tests/perftests/core/AndroidManifest.xml
+++ b/apct-tests/perftests/core/AndroidManifest.xml
@@ -10,20 +10,33 @@
     <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" />
+    <uses-permission android:name="android.permission.VIBRATE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
-        <activity android:name="android.perftests.utils.PerfTestActivity">
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
           <intent-filter>
             <action android:name="com.android.perftests.core.PERFTEST" />
           </intent-filter>
         </activity>
-        <service android:name="android.os.SomeService" android:exported="false" android:process=":some_service" />
+
+        <service
+            android:name="android.os.SomeService"
+            android:exported="false"
+            android:process=":some_service" />
+
+        <provider
+            android:name="android.os.SomeProvider"
+            android:authorities="android.os.SomeProvider"
+            android:exported="false"
+            android:process=":some_provider" />
 
         <service
             android:name="android.view.autofill.MyAutofillService"
             android:label="PERF AutofillService"
-            android:permission="android.permission.BIND_AUTOFILL_SERVICE" >
+            android:permission="android.permission.BIND_AUTOFILL_SERVICE"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.service.autofill.AutofillService" />
             </intent-filter>
@@ -31,7 +44,7 @@
 
     </application>
 
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.benchmark.junit4.AndroidBenchmarkRunner"
         android:targetPackage="com.android.perftests.core"/>
 
 </manifest>
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 1b28913..4f8ee29 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -16,13 +16,40 @@
 <configuration description="Runs CorePerfTests metric instrumentation.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-metric-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CorePerfTests.apk" />
     </target_preparer>
 
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto files in external storage-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.core" />
         <option name="hidden-api-checks" value="false"/>
+
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
     </test>
 </configuration>
diff --git a/apct-tests/perftests/core/OWNERS b/apct-tests/perftests/core/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/apct-tests/perftests/core/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/apct-tests/perftests/core/apps/overlay/Android.bp b/apct-tests/perftests/core/apps/overlay/Android.bp
index 7bee30e..6465307 100644
--- a/apct-tests/perftests/core/apps/overlay/Android.bp
+++ b/apct-tests/perftests/core/apps/overlay/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test_helper_app {
     name: "Overlay0",
     aaptflags: [
@@ -185,4 +194,4 @@
         ":LargeOverlay8",
         ":LargeOverlay9",
     ],
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/core/apps/overlay/OWNERS b/apct-tests/perftests/core/apps/overlay/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/apct-tests/perftests/core/apps/overlay/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/apct-tests/perftests/core/apps/reources_manager/Android.bp b/apct-tests/perftests/core/apps/reources_manager/Android.bp
index 4516132..85dd0c4 100644
--- a/apct-tests/perftests/core/apps/reources_manager/Android.bp
+++ b/apct-tests/perftests/core/apps/reources_manager/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test_helper_app {
     name: "LargeResourcesCompressed",
     static_libs: [ "androidx.appcompat_appcompat" ],
@@ -31,4 +40,4 @@
         ":LargeResourcesCompressed",
         ":LargeResourcesUncompressed",
     ],
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/core/jni/Android.bp b/apct-tests/perftests/core/jni/Android.bp
index 4c0f2aa..1e4405de 100644
--- a/apct-tests/perftests/core/jni/Android.bp
+++ b/apct-tests/perftests/core/jni/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 cc_library_shared {
     name: "libperftestscore_jni",
     sdk_version: "21",
@@ -10,4 +19,5 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
+    header_libs: ["jni_headers"],
 }
diff --git a/apct-tests/perftests/core/src/android/accounts/OWNERS b/apct-tests/perftests/core/src/android/accounts/OWNERS
new file mode 100644
index 0000000..df1b4f4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/accounts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/accounts/OWNERS
diff --git a/apct-tests/perftests/core/src/android/app/OWNERS b/apct-tests/perftests/core/src/android/app/OWNERS
new file mode 100644
index 0000000..4f168ce
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/app/OWNERS
@@ -0,0 +1,2 @@
+per-file Overlay* = file:/core/java/android/app/RESOURCES_OWNERS
+per-file Resources* = file:/core/java/android/app/RESOURCES_OWNERS
diff --git a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
index a320514..1bb98cb 100644
--- a/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/PendingIntentPerfTest.java
@@ -62,7 +62,7 @@
             state.resumeTiming();
 
             final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
-                    0);
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             state.pauseTiming();
             pendingIntent.cancel();
@@ -80,11 +80,11 @@
         while (state.keepRunning()) {
             state.pauseTiming();
             final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
-                    mIntent, 0);
+                    mIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
             state.resumeTiming();
 
             final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
-                    PendingIntent.FLAG_CANCEL_CURRENT);
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             state.pauseTiming();
             pendingIntent.cancel();
@@ -102,11 +102,11 @@
         while (state.keepRunning()) {
             state.pauseTiming();
             final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
-                    mIntent, 0);
+                    mIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
             state.resumeTiming();
 
             final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             state.pauseTiming();
             previousPendingIntent.cancel();
@@ -124,7 +124,7 @@
         while (state.keepRunning()) {
             state.pauseTiming();
             final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
-                    mIntent, 0);
+                    mIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
             state.resumeTiming();
 
             pendingIntent.cancel();
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
index 050fecd..ac63653 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
@@ -17,7 +17,6 @@
 
 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;
@@ -78,7 +77,7 @@
     }
 
     private void getResourcesForPath(String path) {
-        ResourcesManager.getInstance().getResources(null, path, null, null, null,
+        ResourcesManager.getInstance().getResources(null, path, null, null, null, null,
                 Display.DEFAULT_DISPLAY, null, sContext.getResources().getCompatibilityInfo(),
                 null, null);
     }
@@ -136,4 +135,22 @@
             }
         }
     }
+
+    @Test
+    public void getDisplayMetrics() {
+        ResourcesManager resourcesManager = ResourcesManager.getInstance();
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Invalidate cache.
+            resourcesManager.applyConfigurationToResources(
+                    resourcesManager.getConfiguration(), null);
+            state.resumeTiming();
+
+            // Invoke twice for testing cache.
+            resourcesManager.getDisplayMetrics();
+            resourcesManager.getDisplayMetrics();
+        }
+    }
 }
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
index f4c0a17..45c723b 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
@@ -95,8 +95,9 @@
                 ? 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);
+                ai.splitSourceDirs, ai.resourceDirs, ai.overlayPaths, ai.sharedLibraryFiles,
+                Display.DEFAULT_DISPLAY, c, mContext.getResources().getCompatibilityInfo(),
+                null, null);
         Assert.assertNotEquals(destResources.getAssets(), mContext.getAssets());
 
         Resources.Theme destTheme = destResources.newTheme();
diff --git a/apct-tests/perftests/core/src/android/content/pm/PackageManagerBenchmark.java b/apct-tests/perftests/core/src/android/content/pm/PackageManagerBenchmark.java
new file mode 100644
index 0000000..a82fab4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/content/pm/PackageManagerBenchmark.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 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.content.pm;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class PackageManagerBenchmark {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void createUserContextBenchmark() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            context.createContextAsUser(UserHandle.SYSTEM, /* flags */ 0);
+        }
+    }
+
+    @Test
+    public void getResourcesForApplication_byStarAsUser()
+            throws PackageManager.NameNotFoundException {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            context.getPackageManager().getResourcesForApplicationAsUser(context.getPackageName(),
+                    UserHandle.USER_SYSTEM);
+        }
+    }
+
+    @Test
+    public void getResourcesApplication_byCreateContextAsUser()
+            throws PackageManager.NameNotFoundException {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            context.createContextAsUser(UserHandle.SYSTEM, /* flags */ 0).getPackageManager()
+                    .getResourcesForApplication(context.getPackageName());
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/database/CrossProcessCursorPerfTest.java b/apct-tests/perftests/core/src/android/database/CrossProcessCursorPerfTest.java
new file mode 100644
index 0000000..77654df
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/CrossProcessCursorPerfTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 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.database;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.net.Uri;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class CrossProcessCursorPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    /**
+     * Measure transporting a small {@link Cursor}, roughly 1KB in size.
+     */
+    @Test
+    public void timeSmall() throws Exception {
+        time(1);
+    }
+
+    /**
+     * Measure transporting a small {@link Cursor}, roughly 54KB in size.
+     */
+    @Test
+    public void timeMedium() throws Exception {
+        time(100);
+    }
+
+    /**
+     * Measure transporting a small {@link Cursor}, roughly 5.4MB in size.
+     */
+    @Test
+    public void timeLarge() throws Exception {
+        time(10_000);
+    }
+
+    private static final Uri TEST_URI = Uri.parse("content://android.os.SomeProvider/");
+
+    private void time(int count) throws Exception {
+        try (ContentProviderClient client = InstrumentationRegistry.getTargetContext()
+                .getContentResolver().acquireContentProviderClient(TEST_URI)) {
+            // Configure remote side once with data size to return
+            final ContentValues values = new ContentValues();
+            values.put(Intent.EXTRA_INDEX, count);
+            client.update(TEST_URI, values, null);
+
+            // Repeatedly query that data until we reach convergence
+            final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            while (state.keepRunning()) {
+                try (Cursor c = client.query(TEST_URI, null, null, null)) {
+                    // Actually walk the returned values to ensure we pull all
+                    // data from the remote side
+                    while (c.moveToNext()) {
+                        assertEquals(c.getPosition(), c.getInt(0));
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/database/OWNERS b/apct-tests/perftests/core/src/android/database/OWNERS
new file mode 100644
index 0000000..bb9a2ca
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/database/OWNERS
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index 9f09305..f84a0d0 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -54,11 +54,11 @@
             canvas = node.start(200, 200);
             int save = canvas.save();
             canvas.clipRect(1, 1, 199, 199);
-            canvas.insertReorderBarrier();
+            canvas.enableZ();
             for (int i = 0; i < 5; i++) {
                 canvas.drawRenderNode(child);
             }
-            canvas.insertInorderBarrier();
+            canvas.disableZ();
             canvas.restoreToCount(save);
             node.end(canvas);
         }
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
index 8847456..e83c64c 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -27,6 +27,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.Preconditions;
 import com.android.perftests.core.R;
 
 import org.junit.Rule;
@@ -73,10 +74,31 @@
         final AssetManager am = context.getAssets();
 
         while (state.keepRunning()) {
-            Typeface face = Typeface.createFromAsset(am, TEST_FONT_NAME);
+            Typeface face = createFromNonAsset(am, TEST_FONT_NAME);
         }
     }
 
+    /**
+     * {@link AssetManager#openNonAsset(String)} variant of
+     * {@link Typeface#createFromAsset(AssetManager, String)}.
+     */
+    private static Typeface createFromNonAsset(AssetManager mgr, String path) {
+        Preconditions.checkNotNull(path); // for backward compatibility
+        Preconditions.checkNotNull(mgr);
+
+        Typeface typeface = new Typeface.Builder(mgr, path).build();
+        if (typeface != null) return typeface;
+        // check if the file exists, and throw an exception for backward compatibility
+        //noinspection EmptyTryBlock
+        try (InputStream inputStream = mgr.openNonAsset(path)) {
+            // Purposely empty
+        } catch (IOException e) {
+            throw new RuntimeException("Font asset not found " + path);
+        }
+
+        return Typeface.DEFAULT;
+    }
+
     @Test
     public void testCreate_fromFile() {
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
@@ -90,7 +112,7 @@
             throw new RuntimeException(e);
         }
 
-        try (InputStream in = am.open(TEST_FONT_NAME);
+        try (InputStream in = am.openNonAsset(TEST_FONT_NAME);
                 OutputStream out = new FileOutputStream(outFile)) {
             byte[] buf = new byte[1024];
             int n = 0;
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java
new file mode 100644
index 0000000..d272507
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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.graphics.perftests;
+
+import android.graphics.Typeface;
+import android.os.SharedMemory;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.util.ArrayMap;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Map;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceSerializationPerfTest {
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void testSerializeFontMap() throws Exception {
+        Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            Typeface.serializeFontMap(systemFontMap);
+        }
+    }
+
+    @Test
+    public void testDeserializeFontMap() throws Exception {
+        SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap());
+        ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN);
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        ArrayMap<String, Typeface> out = new ArrayMap<>();
+        while (state.keepRunning()) {
+            buffer.position(0);
+            Typeface.deserializeFontMap(buffer, out);
+        }
+    }
+
+    @Test
+    public void testSetSystemFontMap() throws Exception {
+        SharedMemory memory = null;
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Explicitly destroy lazy-loaded typefaces, so that we don't hit the mmap limit
+            // (max_map_count).
+            Typeface.destroySystemFontMap();
+            Typeface.loadPreinstalledSystemFontMap();
+            if (memory != null) {
+                memory.close();
+            }
+            memory = Typeface.serializeFontMap(Typeface.getSystemFontMap());
+            state.resumeTiming();
+            Typeface.setSystemFontMap(memory);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java b/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java
new file mode 100644
index 0000000..fcbfc72
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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.mtp_perf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class AppFusePerfTest {
+    static final int SIZE = 10 * 1024 * 1024; // 10MB
+
+    @Test
+    public void testReadWriteFile() throws IOException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final StorageManager storageManager = context.getSystemService(StorageManager.class);
+
+        final byte[] bytes = new byte[SIZE];
+        final int samples = 100;
+        final double[] readTime = new double[samples];
+        final double[] writeTime = new double[samples];
+
+        for (int i = 0; i < samples; i++) {
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_READ_ONLY, new TestCallback());
+            try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+                    new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+                final long startTime = System.nanoTime();
+                stream.read(bytes);
+                readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+            }
+        }
+
+        for (int i = 0; i < samples; i++) {
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE,
+                    new TestCallback());
+            try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+                    new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+                final long startTime = System.nanoTime();
+                stream.write(bytes);
+                writeTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+            }
+        }
+
+        double readAverage = 0;
+        double writeAverage = 0;
+        double readSquaredAverage = 0;
+        double writeSquaredAverage = 0;
+        for (int i = 0; i < samples; i++) {
+            readAverage += readTime[i];
+            writeAverage += writeTime[i];
+            readSquaredAverage += readTime[i] * readTime[i];
+            writeSquaredAverage += writeTime[i] * writeTime[i];
+        }
+
+        readAverage /= samples;
+        writeAverage /= samples;
+        readSquaredAverage /= samples;
+        writeSquaredAverage /= samples;
+
+        final Bundle results = new Bundle();
+        results.putDouble("readAverage", readAverage);
+        results.putDouble("readStandardDeviation",
+                Math.sqrt(readSquaredAverage - readAverage * readAverage));
+        results.putDouble("writeAverage", writeAverage);
+        results.putDouble("writeStandardDeviation",
+                Math.sqrt(writeSquaredAverage - writeAverage * writeAverage));
+        InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
+    }
+
+    private static class TestCallback extends ProxyFileDescriptorCallback {
+        @Override
+        public long onGetSize() throws ErrnoException {
+            return SIZE;
+        }
+
+        @Override
+        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
+        }
+
+        @Override
+        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
+        }
+
+        @Override
+        public void onFsync() throws ErrnoException {}
+
+        @Override
+        public void onRelease() {}
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/os/OWNERS b/apct-tests/perftests/core/src/android/os/OWNERS
new file mode 100644
index 0000000..a1719c9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/OWNERS
@@ -0,0 +1 @@
+per-file PackageParsingPerfTest.kt = file:/services/core/java/com/android/server/pm/OWNERS
\ No newline at end of file
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 29721c5..90dca25 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -97,11 +97,21 @@
     private val state: BenchmarkState get() = perfStatusReporter.benchmarkState
     private val apks: List<File> get() = params.apks
 
+    private fun safeParse(parser: ParallelParser<*>, file: File) {
+        try {
+            parser.parse(file)
+        } catch (e: Exception) {
+            // ignore
+        }
+    }
+
     @Test
     fun sequentialNoCache() {
         params.cacheDirToParser(null).use { parser ->
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach {
+                    safeParse(parser, it)
+                }
             }
         }
     }
@@ -110,10 +120,10 @@
     fun sequentialCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
-                apks.forEach { parser.parse(it) }
+                apks.forEach { safeParse(parser, it) }
             }
         }
     }
@@ -132,7 +142,7 @@
     fun parallelCached() {
         params.cacheDirToParser(testFolder.newFolder()).use { parser ->
             // Fill the cache
-            apks.forEach { parser.parse(it) }
+            apks.forEach { safeParse(parser, it) }
 
             while (state.keepRunning()) {
                 apks.forEach { parser.submit(it) }
@@ -149,7 +159,15 @@
             PARALLEL_MAX_THREADS, "package-parsing-test",
             Process.THREAD_PRIORITY_FOREGROUND)
 
-        fun submit(file: File) = service.submit { queue.put(parse(file)) }
+        fun submit(file: File) {
+                service.submit {
+                    try {
+                        queue.put(parse(file))
+                    } catch (e: Exception) {
+                        queue.put(e)
+                    }
+                }
+        }
 
         fun take() = queue.poll(QUEUE_POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS)
 
@@ -178,17 +196,17 @@
             // For testing, just disable enforcement to avoid hooking up to compat framework
             ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
         }
-        val parser = ParsingPackageUtils(false, null, null,
+        val parser = ParsingPackageUtils(false, null, null, emptyList(),
             object : ParsingPackageUtils.Callback {
                 override fun hasFeature(feature: String) = true
 
                 override fun startParsingPackage(
                     packageName: String,
-                    baseCodePath: String,
-                    codePath: String,
+                    baseApkPath: String,
+                    path: String,
                     manifestArray: TypedArray,
                     isCoreApp: Boolean
-                ) = ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
+                ) = ParsingPackageImpl(packageName, baseApkPath, path, manifestArray)
             })
 
         override fun parseImpl(file: File) =
diff --git a/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java
new file mode 100644
index 0000000..760ae12
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/ParcelObtainPerfTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class ParcelObtainPerfTest {
+    private static final int ITERATIONS = 1_000_000;
+
+    @Test
+    public void timeContention_01() throws Exception {
+        timeContention(1);
+    }
+
+    @Test
+    public void timeContention_04() throws Exception {
+        timeContention(4);
+    }
+
+    @Test
+    public void timeContention_16() throws Exception {
+        timeContention(16);
+    }
+
+    private static void timeContention(int numThreads) throws Exception {
+        final long start = SystemClock.elapsedRealtime();
+        {
+            final ObtainThread[] threads = new ObtainThread[numThreads];
+            for (int i = 0; i < numThreads; i++) {
+                final ObtainThread thread = new ObtainThread(ITERATIONS / numThreads);
+                thread.start();
+                threads[i] = thread;
+            }
+            for (int i = 0; i < numThreads; i++) {
+                threads[i].join();
+            }
+        }
+        final long duration = SystemClock.elapsedRealtime() - start;
+
+        final Bundle results = new Bundle();
+        results.putLong("duration", duration);
+        InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+    }
+
+    public static class ObtainThread extends Thread {
+        public int iterations;
+
+        public ObtainThread(int iterations) {
+            this.iterations = iterations;
+        }
+
+        @Override
+        public void run() {
+            while (iterations-- > 0) {
+                final Parcel data = Parcel.obtain();
+                final Parcel reply = Parcel.obtain();
+                try {
+                    data.writeInt(32);
+                    reply.writeInt(32);
+                } finally {
+                    reply.recycle();
+                    data.recycle();
+                }
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
index 4db9262..be2f9d7 100644
--- a/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/ParcelPerfTest.java
@@ -159,21 +159,6 @@
     }
 
     @Test
-    public void timeObtainRecycle() {
-        // Use up the pooled instances.
-        // A lot bigger than the actual size but in case someone increased it.
-        final int POOL_SIZE = 100;
-        for (int i = 0; i < POOL_SIZE; i++) {
-            Parcel.obtain();
-        }
-
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            Parcel.obtain().recycle();
-        }
-    }
-
-    @Test
     public void timeWriteException() {
         timeWriteException(false);
     }
diff --git a/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java
new file mode 100644
index 0000000..2b861cb
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.os;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+
+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;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class ParcelStringPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Parameterized.Parameter(0)
+    public String mName;
+    @Parameterized.Parameter(1)
+    public String mValue;
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Object[]> getParameters() {
+        return Arrays.asList(new Object[][] {
+                { "simple", "com.example.typical_package_name" },
+                { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" },
+        });
+    }
+
+    @Test
+    public void timeWriteString8() {
+        final Parcel parcel = Parcel.obtain();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            parcel.setDataPosition(0);
+            parcel.writeString8(mValue);
+        }
+    }
+
+    @Test
+    public void timeWriteString16() {
+        final Parcel parcel = Parcel.obtain();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            parcel.setDataPosition(0);
+            parcel.writeString16(mValue);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/os/SomeProvider.java b/apct-tests/perftests/core/src/android/os/SomeProvider.java
new file mode 100644
index 0000000..f5e247e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/SomeProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.os;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+
+import java.util.Arrays;
+
+public class SomeProvider extends ContentProvider {
+    private Cursor mCursor;
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return mCursor;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        final char[] valueRaw = new char[512];
+        Arrays.fill(valueRaw, '!');
+        final String value = new String(valueRaw);
+
+        final int count = values.getAsInteger(Intent.EXTRA_INDEX);
+        final MatrixCursor cursor = new MatrixCursor(new String[] { "_id", "value" });
+        for (int i = 0; i < count; i++) {
+            MatrixCursor.RowBuilder row = cursor.newRow();
+            row.add(0, i);
+            row.add(1, value);
+        }
+        mCursor = cursor;
+        return 1;
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
new file mode 100644
index 0000000..0efe8cf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 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.os;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.content.Context;
+
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+@LargeTest
+public class VibratorPerfTest {
+    @Rule
+    public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+
+    private Vibrator mVibrator;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mVibrator = context.getSystemService(Vibrator.class);
+    }
+
+    @Test
+    public void testEffectClick() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        while (state.keepRunning()) {
+            mVibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        }
+    }
+
+    @Test
+    public void testOneShot() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        while (state.keepRunning()) {
+            mVibrator.vibrate(VibrationEffect.createOneShot(SECONDS.toMillis(2),
+                    VibrationEffect.DEFAULT_AMPLITUDE));
+        }
+    }
+
+    @Test
+    public void testWaveform() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        long[] timings = new long[]{SECONDS.toMillis(1), SECONDS.toMillis(2), SECONDS.toMillis(1)};
+        while (state.keepRunning()) {
+            mVibrator.vibrate(VibrationEffect.createWaveform(timings, -1));
+        }
+    }
+
+    @Test
+    public void testCompose() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        while (state.keepRunning()) {
+            mVibrator.vibrate(
+                    VibrationEffect.startComposition()
+                            .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK)
+                            .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, 100)
+                            .compose());
+        }
+    }
+
+    @Test
+    public void testAreEffectsSupported() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
+        while (state.keepRunning()) {
+            mVibrator.areEffectsSupported(effects);
+        }
+    }
+
+    @Test
+    public void testArePrimitivesSupported() {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        int[] primitives = new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK,
+                VibrationEffect.Composition.PRIMITIVE_TICK};
+        while (state.keepRunning()) {
+            mVibrator.arePrimitivesSupported(primitives);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
index bb6b691..66b2b0e 100644
--- a/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
+++ b/apct-tests/perftests/core/src/android/text/CanvasDrawTextTest.java
@@ -53,19 +53,19 @@
         final String text = mTextUtil.nextRandomParagraph(
                 WORD_LENGTH, 4 * 1024 * 1024 /* 4mb text */).toString();
         final RenderNode node = RenderNode.create("benchmark", null);
-        final RenderNode child = RenderNode.create("child", null);
-        child.setLeftTopRightBottom(50, 50, 100, 100);
-
-        RecordingCanvas canvas = node.start(100, 100);
-        node.end(canvas);
-        canvas = child.start(50, 50);
-        child.end(canvas);
 
         final Random r = new Random(0);
-
         while (state.keepRunning()) {
+            state.pauseTiming();
+            RecordingCanvas canvas = node.beginRecording();
             int start = r.nextInt(text.length() - 100);
+            state.resumeTiming();
+
             canvas.drawText(text, start, start + 100, 0, 0, PAINT);
+
+            state.pauseTiming();
+            node.endRecording();
+            state.resumeTiming();
         }
     }
 }
diff --git a/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java b/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java
new file mode 100644
index 0000000..5d744cd
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/SystemFontsPerfTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 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.text;
+
+import android.graphics.fonts.SystemFonts;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class SystemFontsPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void getAvailableFonts() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            SystemFonts.resetAvailableFonts();
+            System.gc();
+            state.resumeTiming();
+
+            SystemFonts.getAvailableFonts();
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/text/TextUtilsPerfTest.java b/apct-tests/perftests/core/src/android/text/TextUtilsPerfTest.java
new file mode 100644
index 0000000..c62269e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/TextUtilsPerfTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.text;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class TextUtilsPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    public static final String TEMPLATE = "Template that combines %s and %d together";
+
+    public String mVar1 = "example";
+    public int mVar2 = 42;
+
+    /**
+     * Measure overhead of formatting a string via {@link String#format}.
+     */
+    @Test
+    public void timeFormatUpstream() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            String res = String.format(TEMPLATE, mVar1, mVar2);
+        }
+    }
+
+    /**
+     * Measure overhead of formatting a string via
+     * {@link TextUtils#formatSimple}.
+     */
+    @Test
+    public void timeFormatLocal() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            String res = TextUtils.formatSimple(TEMPLATE, mVar1, mVar2);
+        }
+    }
+
+    /**
+     * Measure overhead of formatting a string inline.
+     */
+    @Test
+    public void timeFormatInline() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            String res = "Template that combines " + mVar1 + " and " + mVar2 + " together";
+        }
+    }
+
+    /**
+     * Measure overhead of a passing null-check that uses a lambda to
+     * communicate a custom error message.
+     */
+    @Test
+    public void timeFormat_Skip_Lambda() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            requireNonNull(this, () -> {
+                return String.format(TEMPLATE, mVar1, mVar2);
+            });
+        }
+    }
+
+    /**
+     * Measure overhead of a passing null-check that uses varargs to communicate
+     * a custom error message.
+     */
+    @Test
+    public void timeFormat_Skip_Varargs() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            requireNonNull(this, TEMPLATE, mVar1, mVar2);
+        }
+    }
+
+    private static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
+        return obj;
+    }
+
+    private static <T> T requireNonNull(T obj, String format, Object... args) {
+        return obj;
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
new file mode 100644
index 0000000..fbe67a4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/text/VariableFontPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 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.text;
+
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class VariableFontPerfTest {
+    private static final int WORD_LENGTH = 9;  // Random word has 9 characters.
+    private static final boolean NO_STYLE_TEXT = false;
+
+    private static final TextPaint PAINT = new TextPaint();
+
+    public VariableFontPerfTest() {}
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private final TextPerfUtils mTextUtil = new TextPerfUtils();
+
+    @Before
+    public void setUp() {
+        mTextUtil.resetRandom(0 /* seed */);
+    }
+
+    @Test
+    public void testDraw_SetVariationOnce() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+        final Paint paint = new Paint(PAINT);
+        paint.setFontVariationSettings("'wght' 700");
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final RecordingCanvas c = node.beginRecording(1200, 200);
+            state.resumeTiming();
+
+            c.drawText(text, 0, text.length(), 0, 100, paint);
+
+            state.pauseTiming();
+            node.endRecording();
+            state.resumeTiming();
+
+        }
+    }
+
+    @Test
+    public void testDraw_SetVariationEachDraw() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+        final Paint paint = new Paint(PAINT);
+        final RenderNode node = RenderNode.create("benchmark", null);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final RecordingCanvas c = node.beginRecording(1200, 200);
+            paint.setFontVariationSettings("'wght' 700");
+            state.resumeTiming();
+
+            c.drawText(text, 0, text.length(), 0, 100, paint);
+
+            state.pauseTiming();
+            node.endRecording();
+            state.resumeTiming();
+
+        }
+    }
+
+    @Test
+    public void testDraw_SetDifferentVariationEachDraw() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
+        final Paint paint = new Paint(PAINT);
+        final RenderNode node = RenderNode.create("benchmark", null);
+        final Random random = new Random(0);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            final RecordingCanvas c = node.beginRecording(1200, 200);
+            int weight = random.nextInt(1000);
+            paint.setFontVariationSettings("'wght' " + weight);
+            state.resumeTiming();
+
+            c.drawText(text, 0, text.length(), 0, 100, paint);
+
+            state.pauseTiming();
+            node.endRecording();
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void testSetFontVariationSettings() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Paint paint = new Paint(PAINT);
+        final Random random = new Random(0);
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            int weight = random.nextInt(1000);
+            state.resumeTiming();
+
+            paint.setFontVariationSettings("'wght' " + weight);
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
new file mode 100644
index 0000000..e2c580c
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class CharsetUtilsPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Parameterized.Parameter(0)
+    public String mName;
+    @Parameterized.Parameter(1)
+    public String mValue;
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Object[]> getParameters() {
+        return Arrays.asList(new Object[][] {
+                { "simple", "com.example.typical_package_name" },
+                { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" },
+        });
+    }
+
+    @Test
+    public void timeUpstream() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mValue.getBytes(StandardCharsets.UTF_8);
+        }
+    }
+
+    /**
+     * Measure performance of writing into a small buffer where bounds checking
+     * requires careful measurement of encoded size.
+     */
+    @Test
+    public void timeLocal_SmallBuffer() {
+        final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 64);
+        final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            CharsetUtils.toModifiedUtf8Bytes(mValue, destPtr, 0, dest.length);
+        }
+    }
+
+    /**
+     * Measure performance of writing into a large buffer where bounds checking
+     * only needs a simple worst-case 4-bytes-per-char check.
+     */
+    @Test
+    public void timeLocal_LargeBuffer() {
+        final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 1024);
+        final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            CharsetUtils.toModifiedUtf8Bytes(mValue, destPtr, 0, dest.length);
+       }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/util/XmlPerfTest.java b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
new file mode 100644
index 0000000..e05bd2a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Bundle;
+import android.os.Debug;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class XmlPerfTest {
+    /**
+     * Since allocation measurement adds overhead, it's disabled by default for
+     * performance runs. It can be manually enabled to compare GC behavior.
+     */
+    private static final boolean MEASURE_ALLOC = false;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void timeWrite_Fast() throws Exception {
+        doWrite(() -> Xml.newFastSerializer());
+    }
+
+    @Test
+    public void timeWrite_Binary() throws Exception {
+        doWrite(() -> Xml.newBinarySerializer());
+    }
+
+    private void doWrite(Supplier<TypedXmlSerializer> outFactory) throws Exception {
+        if (MEASURE_ALLOC) {
+            Debug.startAllocCounting();
+        }
+
+        int iterations = 0;
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            iterations++;
+            try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                final TypedXmlSerializer out = outFactory.get();
+                out.setOutput(os, StandardCharsets.UTF_8.name());
+                write(out);
+            }
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.stopAllocCounting();
+            final Bundle results = new Bundle();
+            results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+            results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        }
+    }
+
+    @Test
+    public void timeRead_Fast() throws Exception {
+        doRead(() -> Xml.newFastSerializer(), () -> Xml.newFastPullParser());
+    }
+
+    @Test
+    public void timeRead_Binary() throws Exception {
+        doRead(() -> Xml.newBinarySerializer(), () -> Xml.newBinaryPullParser());
+    }
+
+    private void doRead(Supplier<TypedXmlSerializer> outFactory,
+            Supplier<TypedXmlPullParser> inFactory) throws Exception {
+        final byte[] raw;
+        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            TypedXmlSerializer out = outFactory.get();
+            out.setOutput(os, StandardCharsets.UTF_8.name());
+            write(out);
+            raw = os.toByteArray();
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.startAllocCounting();
+        }
+
+        int iterations = 0;
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            iterations++;
+            try (ByteArrayInputStream is = new ByteArrayInputStream(raw)) {
+                TypedXmlPullParser xml = inFactory.get();
+                xml.setInput(is, StandardCharsets.UTF_8.name());
+                read(xml);
+            }
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.stopAllocCounting();
+            final Bundle results = new Bundle();
+            results.putLong("sizeBytes", raw.length);
+            results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+            results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        } else {
+            final Bundle results = new Bundle();
+            results.putLong("sizeBytes", raw.length);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        }
+    }
+
+    /**
+     * Not even joking, this is a typical public key blob stored in
+     * {@code packages.xml}.
+     */
+    private static final byte[] KEY_BLOB = HexDump.hexStringToByteArray(""
+            + "308204a830820390a003020102020900a1573d0f45bea193300d06092a864886f70d010105050030819"
+            + "4310b3009060355040613025553311330110603550408130a43616c69666f726e696131163014060355"
+            + "0407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e06035"
+            + "5040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d"
+            + "0109011613616e64726f696440616e64726f69642e636f6d301e170d3131303931393138343232355a1"
+            + "70d3339303230343138343232355a308194310b3009060355040613025553311330110603550408130a"
+            + "43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e0603550"
+            + "40a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e"
+            + "64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d3"
+            + "0820120300d06092a864886f70d01010105000382010d00308201080282010100de1b51336afc909d8b"
+            + "cca5920fcdc8940578ec5c253898930e985481cfdea75ba6fc54b1f7bb492a03d98db471ab4200103a8"
+            + "314e60ee25fef6c8b83bc1b2b45b084874cffef148fa2001bb25c672b6beba50b7ac026b546da762ea2"
+            + "23829a22b80ef286131f059d2c9b4ca71d54e515a8a3fd6bf5f12a2493dfc2619b337b032a7cf8bbd34"
+            + "b833f2b93aeab3d325549a93272093943bb59dfc0197ae4861ff514e019b73f5cf10023ad1a032adb4b"
+            + "9bbaeb4debecb4941d6a02381f1165e1ac884c1fca9525c5854dce2ad8ec839b8ce78442c16367efc07"
+            + "778a337d3ca2cdf9792ac722b95d67c345f1c00976ec372f02bfcbef0262cc512a6845e71cfea0d0201"
+            + "03a381fc3081f9301d0603551d0e0416041478a0fc4517fb70ff52210df33c8d32290a44b2bb3081c90"
+            + "603551d230481c13081be801478a0fc4517fb70ff52210df33c8d32290a44b2bba1819aa48197308194"
+            + "310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550"
+            + "407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355"
+            + "040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0"
+            + "109011613616e64726f696440616e64726f69642e636f6d820900a1573d0f45bea193300c0603551d13"
+            + "040530030101ff300d06092a864886f70d01010505000382010100977302dfbf668d7c61841c9c78d25"
+            + "63bcda1b199e95e6275a799939981416909722713531157f3cdcfea94eea7bb79ca3ca972bd8058a36a"
+            + "d1919291df42d7190678d4ea47a4b9552c9dfb260e6d0d9129b44615cd641c1080580e8a990dd768c6a"
+            + "b500c3b964e185874e4105109d94c5bd8c405deb3cf0f7960a563bfab58169a956372167a7e2674a04c"
+            + "4f80015d8f7869a7a4139aecbbdca2abc294144ee01e4109f0e47a518363cf6e9bf41f7560e94bdd4a5"
+            + "d085234796b05c7a1389adfd489feec2a107955129d7991daa49afb3d327dc0dc4fe959789372b093a8"
+            + "9c8dbfa41554f771c18015a6cb242a17e04d19d55d3b4664eae12caf2a11cd2b836e");
+
+    /**
+     * Typical list of permissions referenced in {@code packages.xml}.
+     */
+    private static final String[] PERMS = new String[] {
+            "android.permission.ACCESS_CACHE_FILESYSTEM",
+            "android.permission.WRITE_SETTINGS",
+            "android.permission.MANAGE_EXTERNAL_STORAGE",
+            "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS",
+            "android.permission.FOREGROUND_SERVICE",
+            "android.permission.RECEIVE_BOOT_COMPLETED",
+            "android.permission.WRITE_MEDIA_STORAGE",
+            "android.permission.INTERNET",
+            "android.permission.UPDATE_DEVICE_STATS",
+            "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY",
+            "android.permission.MANAGE_USB",
+            "android.permission.ACCESS_ALL_DOWNLOADS",
+            "android.permission.ACCESS_DOWNLOAD_MANAGER",
+            "android.permission.MANAGE_USERS",
+            "android.permission.ACCESS_NETWORK_STATE",
+            "android.permission.ACCESS_MTP",
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS",
+            "android.permission.CLEAR_APP_CACHE",
+            "android.permission.CONNECTIVITY_INTERNAL",
+            "android.permission.START_ACTIVITIES_FROM_BACKGROUND",
+            "android.permission.QUERY_ALL_PACKAGES",
+            "android.permission.WAKE_LOCK",
+            "android.permission.UPDATE_APP_OPS_STATS",
+    };
+
+    /**
+     * Write a typical {@code packages.xml} file containing 100 applications,
+     * each of which defines signing key and permission information.
+     */
+    private static void write(TypedXmlSerializer out) throws IOException {
+        out.startDocument(null, true);
+        out.startTag(null, "packages");
+        for (int i = 0; i < 100; i++) {
+            out.startTag(null, "package");
+            out.attribute(null, "name", "com.android.providers.media");
+            out.attribute(null, "codePath", "/system/priv-app/MediaProviderLegacy");
+            out.attribute(null, "nativeLibraryPath", "/system/priv-app/MediaProviderLegacy/lib");
+            out.attributeLong(null, "publicFlags", 944258629L);
+            out.attributeLong(null, "privateFlags", -1946152952L);
+            out.attributeLong(null, "ft", 1603899064000L);
+            out.attributeLong(null, "it", 1603899064000L);
+            out.attributeLong(null, "ut", 1603899064000L);
+            out.attributeInt(null, "version", 1024);
+            out.attributeInt(null, "sharedUserId", 10100);
+            out.attributeBoolean(null, "isOrphaned", true);
+
+            out.startTag(null, "sigs");
+            out.startTag(null, "cert");
+            out.attributeInt(null, "index", 10);
+            out.attributeBytesHex(null, "key", KEY_BLOB);
+            out.endTag(null, "cert");
+            out.endTag(null, "sigs");
+
+            out.startTag(null, "perms");
+            for (String perm : PERMS) {
+                out.startTag(null, "item");
+                out.attributeInterned(null, "name", perm);
+                out.attributeBoolean(null, "granted", true);
+                out.attributeInt(null, "flags", 0);
+                out.endTag(null, "item");
+            }
+            out.endTag(null, "perms");
+
+            out.endTag(null, "package");
+        }
+        out.endTag(null, "packages");
+        out.endDocument();
+    }
+
+    /**
+     * Read a typical {@code packages.xml} file containing 100 applications, and
+     * verify that data passes smell test.
+     */
+    private static void read(TypedXmlPullParser xml) throws Exception {
+        int type;
+        int packages = 0;
+        int certs = 0;
+        int perms = 0;
+        while ((type = xml.next()) != XmlPullParser.END_DOCUMENT) {
+            final String tag = xml.getName();
+            if (type == XmlPullParser.START_TAG) {
+                if ("package".equals(tag)) {
+                    xml.getAttributeValue(null, "name");
+                    xml.getAttributeValue(null, "codePath");
+                    xml.getAttributeValue(null, "nativeLibraryPath");
+                    xml.getAttributeLong(null, "publicFlags");
+                    assertEquals(-1946152952L, xml.getAttributeLong(null, "privateFlags"));
+                    xml.getAttributeLong(null, "ft");
+                    xml.getAttributeLong(null, "it");
+                    xml.getAttributeLong(null, "ut");
+                    xml.getAttributeInt(null, "version");
+                    xml.getAttributeInt(null, "sharedUserId");
+                    xml.getAttributeBoolean(null, "isOrphaned");
+                    packages++;
+                } else if ("cert".equals(tag)) {
+                    xml.getAttributeInt(null, "index");
+                    xml.getAttributeBytesHex(null, "key");
+                    certs++;
+                } else if ("item".equals(tag)) {
+                    xml.getAttributeValue(null, "name");
+                    xml.getAttributeBoolean(null, "granted");
+                    xml.getAttributeInt(null, "flags");
+                    perms++;
+                }
+            } else if (type == XmlPullParser.TEXT) {
+                xml.getText();
+            }
+        }
+
+        assertEquals(100, packages);
+        assertEquals(packages * 1, certs);
+        assertEquals(packages * PERMS.length, perms);
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
index 14282bf..860c134 100644
--- a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
+++ b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
@@ -16,24 +16,20 @@
 
 package android.view;
 
-import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.PathParser;
 
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
 import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -41,6 +37,10 @@
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class CutoutSpecificationBenchmark {
+    private static final int DISPLAY_WIDTH = 1080;
+    private static final int DISPLAY_HEIGHT = 1920;
+    private static final float DISPLAY_DENSITY = 3.5f;
+
     private static final String TAG = "CutoutSpecificationBenchmark";
 
     private static final String BOTTOM_MARKER = "@bottom";
@@ -67,22 +67,7 @@
             + "Z\n"
             + "@dp";
     @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
-    private Context mContext;
-    private DisplayMetrics mDisplayMetrics;
-
-    /**
-     * Setup the necessary member field used by test methods.
-     */
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-        mDisplayMetrics = new DisplayMetrics();
-        mContext.getDisplay().getRealMetrics(mDisplayMetrics);
-    }
-
+    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
 
     private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
         final RectF rectF = new RectF();
@@ -168,19 +153,18 @@
 
     @Test
     public void parseByOldMethodForDoubleCutout() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
-            oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, mDisplayMetrics.widthPixels,
-                    mDisplayMetrics.heightPixels, mDisplayMetrics.density);
+            oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+                    DISPLAY_DENSITY);
         }
     }
 
     @Test
     public void parseByNewMethodForDoubleCutout() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
-            new CutoutSpecification.Parser(mDisplayMetrics.density,
-                    mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)
+            new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
                     .parse(DOUBLE_CUTOUT_SPEC);
         }
     }
@@ -209,10 +193,10 @@
                 + "@right\n"
                 + "@dp";
 
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
-            new CutoutSpecification.Parser(mDisplayMetrics.density,
-                    mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+            new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
+                    .parse(spec);
         }
     }
 
@@ -231,10 +215,10 @@
                 + "Z\n"
                 + "@dp";
 
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
-            new CutoutSpecification.Parser(mDisplayMetrics.density,
-                    mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+            new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
+                    .parse(spec);
         }
     }
 }
diff --git a/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java b/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java
new file mode 100644
index 0000000..b45dbcf
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2020 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.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.PerfTestActivity;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+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.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class InputStageBenchmark {
+    @Parameterized.Parameters(name = "mShowIme({0}), mHandlePreIme({1})")
+    public static Collection cases() {
+        return Arrays.asList(new Object[][] {
+                { false /* no ime */, false /* skip preime */},
+                { true /* show ime */, false /* skip preime */},
+                { true /* show ime */, true /* handle preime */}
+        });
+    }
+
+    @Rule
+    public final ActivityTestRule<PerfTestActivity> mActivityRule =
+            new ActivityTestRule<>(PerfTestActivity.class);
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Parameterized.Parameter(0)
+    public boolean mShowIme;
+    @Parameterized.Parameter(1)
+    public boolean mHandlePreIme;
+
+    private Instrumentation mInstrumentation;
+    private Window mWindow;
+    private CountDownLatch mWaitForReceiveInput;
+    private static final long TIMEOUT_MS = 5000;
+
+    class InstrumentedView extends View {
+        InstrumentedView(Context context) {
+            super(context);
+            setFocusable(true);
+        }
+
+        @Override
+        public boolean dispatchKeyEventPreIme(KeyEvent event) {
+            if (mHandlePreIme) {
+                mWaitForReceiveInput.countDown();
+            }
+            return mHandlePreIme;
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent event) {
+            mWaitForReceiveInput.countDown();
+            return true;
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            mWaitForReceiveInput.countDown();
+            return true;
+        }
+    }
+
+    class InstrumentedEditText extends EditText {
+        InstrumentedEditText(Context context) {
+            super(context);
+            setFocusable(true);
+        }
+
+        @Override
+        public boolean dispatchKeyEventPreIme(KeyEvent event) {
+            if (mHandlePreIme) {
+                mWaitForReceiveInput.countDown();
+            }
+            return mHandlePreIme;
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent event) {
+            mWaitForReceiveInput.countDown();
+            return true;
+        }
+
+        @Override
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            mWaitForReceiveInput.countDown();
+            return true;
+        }
+    }
+
+    private CountDownLatch showSoftKeyboard(View view) {
+        final CountDownLatch waitForIme = new CountDownLatch(1);
+        view.setOnApplyWindowInsetsListener((v, insets) -> {
+            if (insets.isVisible(WindowInsets.Type.ime())) {
+                waitForIme.countDown();
+            }
+            return insets;
+        });
+
+        assertTrue("Failed to request focus.", view.requestFocus());
+        final InputMethodManager imm =
+                mActivityRule.getActivity().getSystemService(InputMethodManager.class);
+        imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
+
+        return waitForIme;
+    }
+
+    @Before
+    public void setUp() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        final Activity activity = mActivityRule.getActivity();
+
+        final CountDownLatch[] waitForIme = new CountDownLatch[1];
+        mInstrumentation.runOnMainSync(() -> {
+            mWindow = mActivityRule.getActivity().getWindow();
+
+            if (mShowIme) {
+                final EditText edit = new InstrumentedEditText(activity);
+                mWindow.setContentView(edit);
+                waitForIme[0] = showSoftKeyboard(edit);
+            } else {
+                final View v = new InstrumentedView(activity);
+                // set FLAG_LOCAL_FOCUS_MODE to prevent delivering input events to the ime
+                // in ImeInputStage.
+                mWindow.addFlags(WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE);
+                mWindow.setContentView(v);
+                assertTrue("Failed to request focus.", v.requestFocus());
+            }
+        });
+        if (waitForIme[0] != null) {
+            try {
+                assertTrue("Failed to show InputMethod.",
+                        waitForIme[0].await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void injectInputEvent(InputEvent event) {
+        mWaitForReceiveInput = new CountDownLatch(1);
+        mInstrumentation.runOnMainSync(() -> mWindow.injectInputEvent(event));
+        try {
+            mWaitForReceiveInput.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void testKeyEvent() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            final KeyEvent eventDown =
+                    new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACKSLASH);
+            injectInputEvent(eventDown);
+
+            state.pauseTiming();
+            final KeyEvent eventUp =
+                    new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACKSLASH);
+            injectInputEvent(eventUp);
+            state.resumeTiming();
+        }
+    }
+
+    @Test
+    public void testMotionEvent() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Rect contentFrame = new Rect();
+        mInstrumentation.runOnMainSync(() ->
+                mWindow.getDecorView().getBoundsOnScreen(contentFrame));
+        final int x = contentFrame.centerX();
+        final int y = contentFrame.centerY();
+        final long eventTime = SystemClock.uptimeMillis();
+
+        while (state.keepRunning()) {
+            final MotionEvent eventDown = MotionEvent.obtain(eventTime, eventTime,
+                    MotionEvent.ACTION_DOWN, x, y,
+                    1.0f /* pressure */, 1.0f /* size */, 0 /* metaState */,
+                    1.0f /* xPrecision */, 1.0f /* yPrecision */,
+                    0 /* deviceId */, 0 /* edgeFlags */,
+                    InputDevice.SOURCE_TOUCHSCREEN, DEFAULT_DISPLAY);
+            injectInputEvent(eventDown);
+
+            state.pauseTiming();
+            final MotionEvent eventUp = MotionEvent.obtain(eventTime, eventTime,
+                    MotionEvent.ACTION_UP, x, y,
+                    1.0f /* pressure */, 1.0f /* size */, 0 /* metaState */,
+                    1.0f /* xPrecision */, 1.0f /* yPrecision */,
+                    0 /* deviceId */, 0 /* edgeFlags */,
+                    InputDevice.SOURCE_TOUCHSCREEN, DEFAULT_DISPLAY);
+            injectInputEvent(eventUp);
+            state.resumeTiming();
+        }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
index a1f8608..a2aeb31 100644
--- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
@@ -16,30 +16,45 @@
 
 package android.view;
 
+import static junit.framework.Assert.assertTrue;
+
 import android.content.Context;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.PerfTestActivity;
 import android.widget.FrameLayout;
 
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.perftests.core.R;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
 @LargeTest
 public class ViewPerfTest {
     @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+
+    @Rule
+    public final ActivityTestRule<PerfTestActivity> mActivityRule =
+            new ActivityTestRule<>(PerfTestActivity.class);
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+    }
 
     @Test
     public void testSimpleViewInflate() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        LayoutInflater inflater = LayoutInflater.from(context);
-        FrameLayout root = new FrameLayout(context);
+        final BenchmarkState state = mBenchmarkRule.getState();
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        FrameLayout root = new FrameLayout(mContext);
         while (state.keepRunning()) {
             inflater.inflate(R.layout.test_simple_view, root, false);
         }
@@ -47,12 +62,33 @@
 
     @Test
     public void testTwelveKeyInflate() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        LayoutInflater inflater = LayoutInflater.from(context);
-        FrameLayout root = new FrameLayout(context);
+        final BenchmarkState state = mBenchmarkRule.getState();
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        FrameLayout root = new FrameLayout(mContext);
         while (state.keepRunning()) {
             inflater.inflate(R.layout.twelve_key_entry, root, false);
         }
     }
+
+    @Test
+    public void testPerformHapticFeedback() throws Throwable {
+        final BenchmarkState state = mBenchmarkRule.getState();
+        mActivityRule.runOnUiThread(() -> {
+            state.pauseTiming();
+            View view = new View(mContext);
+            mActivityRule.getActivity().setContentView(view);
+            assertTrue("View needs to be attached to Window to perform haptic feedback",
+                    view.isAttachedToWindow());
+            state.resumeTiming();
+
+            // Disable settings so perform will never be ignored.
+            int flags = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
+                    | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING;
+
+            while (state.keepRunning()) {
+                assertTrue("Call to performHapticFeedback was ignored",
+                        view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_PRESS, flags));
+            }
+        });
+    }
 }
diff --git a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
index b0edb11..a69d3ff 100644
--- a/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewShowHidePerfTest.java
@@ -21,14 +21,14 @@
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.PerfTestActivity;
 import android.view.View.MeasureSpec;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
@@ -50,7 +50,7 @@
             new ActivityTestRule<>(PerfTestActivity.class);
 
     @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
 
     public Context getContext() {
         return InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -143,7 +143,7 @@
 
     private void testParentWithChild(TestCallback callback) throws Throwable {
         mActivityRule.runOnUiThread(() -> {
-            final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            final BenchmarkState state = mBenchmarkRule.getState();
 
             FrameLayout parent = new FrameLayout(getContext());
             mActivityRule.getActivity().setContentView(parent);
diff --git a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
index f4ad5dd..c48fa4f 100644
--- a/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
+++ b/apct-tests/perftests/core/src/android/widget/EditTextLongTextPerfTest.java
@@ -43,8 +43,8 @@
     @Parameters(name = "{0}")
     public static Collection cases() {
         return Arrays.asList(new Object[][] {
-            { "10x30K", 10, 30000 },
-            { "300x1K", 300, 1000 },
+            { "10x3K", 10, 3000 },
+            { "30x1K", 30, 1000 },
         });
     }
 
diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
new file mode 100644
index 0000000..2700fff
--- /dev/null
+++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class FastDataPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private static final int OUTPUT_SIZE = 64000;
+    private static final int BUFFER_SIZE = 4096;
+
+    @Test
+    public void timeWrite_Upstream() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            os.reset();
+            final BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
+            final DataOutput out = new DataOutputStream(bos);
+            doWrite(out);
+            bos.flush();
+        }
+    }
+
+    @Test
+    public void timeWrite_Local() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            os.reset();
+            final FastDataOutput out = new FastDataOutput(os, BUFFER_SIZE);
+            doWrite(out);
+            out.flush();
+        }
+    }
+
+    @Test
+    public void timeRead_Upstream() throws Exception {
+        final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            is.reset();
+            final BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
+            final DataInput in = new DataInputStream(bis);
+            doRead(in);
+        }
+    }
+
+    @Test
+    public void timeRead_Local() throws Exception {
+        final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            is.reset();
+            final DataInput in = new FastDataInput(is, BUFFER_SIZE);
+            doRead(in);
+        }
+    }
+
+    /**
+     * Since each iteration is around 64 bytes, we need to iterate many times to
+     * exercise the buffer logic.
+     */
+    private static final int REPEATS = 1000;
+
+    private static byte[] doWrite() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final DataOutput out = new DataOutputStream(os);
+        doWrite(out);
+        return os.toByteArray();
+    }
+
+    private static void doWrite(DataOutput out) throws IOException {
+        for (int i = 0; i < REPEATS; i++) {
+            out.writeByte(Byte.MAX_VALUE);
+            out.writeShort(Short.MAX_VALUE);
+            out.writeInt(Integer.MAX_VALUE);
+            out.writeLong(Long.MAX_VALUE);
+            out.writeFloat(Float.MAX_VALUE);
+            out.writeDouble(Double.MAX_VALUE);
+            out.writeUTF("com.example.typical_package_name");
+        }
+    }
+
+    private static void doRead(DataInput in) throws IOException {
+        for (int i = 0; i < REPEATS; i++) {
+            in.readByte();
+            in.readShort();
+            in.readInt();
+            in.readLong();
+            in.readFloat();
+            in.readDouble();
+            in.readUTF();
+        }
+    }
+}
diff --git a/apct-tests/perftests/inputmethod/Android.bp b/apct-tests/perftests/inputmethod/Android.bp
new file mode 100644
index 0000000..f2f1f75
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "ImePerfTests",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.annotation_annotation",
+        "apct-perftests-utils",
+        "collector-device-lib",
+        "compatibility-device-util-axt",
+        "platform-test-annotations",
+    ],
+    test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/apct-tests/perftests/inputmethod/AndroidManifest.xml b/apct-tests/perftests/inputmethod/AndroidManifest.xml
new file mode 100644
index 0000000..1fb0b88
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.inputmethod">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
+          <intent-filter>
+            <action android:name="com.android.perftests.core.PERFTEST" />
+          </intent-filter>
+        </activity>
+        <service android:name="android.inputmethod.ImePerfTest$BaselineIme"
+                 android:process=":BaselineIME"
+                 android:label="Baseline IME"
+                 android:permission="android.permission.BIND_INPUT_METHOD"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.view.InputMethod"/>
+            </intent-filter>
+            <meta-data android:name="android.view.im"
+                       android:resource="@xml/simple_method"/>
+        </service>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.perftests.inputmethod">
+        <meta-data android:name="listener" android:value="android.inputmethod.ImePerfRunPrecondition" />
+    </instrumentation>
+</manifest>
diff --git a/apct-tests/perftests/inputmethod/AndroidTest.xml b/apct-tests/perftests/inputmethod/AndroidTest.xml
new file mode 100644
index 0000000..1ec0cba
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/AndroidTest.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs ImePerfTests metric instrumentation.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="ImePerfTests.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <option name="force-skip-system-props" value="true" />
+        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+        <option name="run-command" value="cmd window dismiss-keyguard" />
+        <option name="run-command" value="cmd package compile -m speed com.android.perftests.inputmethod" />
+    </target_preparer>
+
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+        <!--Install the content provider automatically when we push some file in sdcard folder.-->
+        <!--Needed to avoid the installation during the test suite.-->
+        <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
+    </target_preparer>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.perftests.inputmethod" />
+        <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- Kill background operations -->
+        <option name="instrumentation-arg" key="kill-bg" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+    </test>
+
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="directory-keys" value="/data/local/tmp/ImePerfTests" />
+        <!-- Needed for pulling the collected trace config on to the host -->
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+</configuration>
diff --git a/apct-tests/perftests/inputmethod/OWNERS b/apct-tests/perftests/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/apct-tests/perftests/inputmethod/README.md b/apct-tests/perftests/inputmethod/README.md
new file mode 100644
index 0000000..8ba2087
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/README.md
@@ -0,0 +1,40 @@
+## IMF performance tests
+
+These tests are adaptation of Window Manager perf tests (apct-tests/perftests/windowmanager).
+
+### Precondition
+To reduce the variance of the test, if `perf-setup` (platform_testing/scripts/perf-setup)
+is available, it is better to use the following instructions to lock CPU and GPU frequencies.
+```
+m perf-setup
+PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh
+adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH
+adb shell chmod +x $PERF_SETUP_PATH
+adb shell $PERF_SETUP_PATH
+```
+
+### Example to run
+Use `atest`
+```
+atest ImePerfTests:ImePerfTest -- \
+      --module-arg ImePerfTests:instrumentation-arg:profiling-iterations:=20
+
+```
+Note: `instrumentation-arg:kill-bg:=true` is already defined in the AndroidText.xml
+
+Use `am instrument`
+```
+adb shell am instrument -w -r -e class android.inputmethod.ImePerfTest \
+          -e listener android.inputmethod.ImePerfRunPrecondition \
+          -e kill-bg true \
+          com.android.perftests.inputmethod/androidx.test.runner.AndroidJUnitRunner
+```
+* `kill-bg` is optional.
+
+Test arguments
+ - kill-bg
+   * boolean: Kill background process before running test.
+ - profiling-iterations
+   * int: Run the extra iterations with enabling method profiling.
+ - profiling-sampling
+   * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/apct-tests/perftests/inputmethod/res/xml/simple_method.xml b/apct-tests/perftests/inputmethod/res/xml/simple_method.xml
new file mode 100644
index 0000000..87cb1ad
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/res/xml/simple_method.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<!-- Configuration info for an input method -->
+<input-method xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
new file mode 100644
index 0000000..4bfcade
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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.inputmethod;
+
+import android.perftests.utils.WindowPerfRunPreconditionBase;
+
+/** Prepare the preconditions before running performance test. */
+public class ImePerfRunPrecondition extends WindowPerfRunPreconditionBase {
+}
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
new file mode 100644
index 0000000..ab3c50b
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2020 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.inputmethod;
+
+import static android.perftests.utils.ManualBenchmarkState.StatsReport;
+import static android.perftests.utils.PerfTestActivity.ID_EDITOR;
+import static android.perftests.utils.TestUtils.getOnMainSync;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.UiThread;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.inputmethodservice.InputMethodService;
+import android.os.Process;
+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.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsController;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.LargeTest;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import junit.framework.Assert;
+
+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.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/** Measure the performance of internal methods in Input Method framework by trace tag. */
+@LargeTest
+public class ImePerfTest extends ImePerfTestBase
+        implements ManualBenchmarkState.CustomizedIterationListener {
+    private static final String TAG = ImePerfTest.class.getSimpleName();
+    private static final long ANIMATION_NOT_STARTED = -1;
+
+    @Rule
+    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+    @Rule
+    public final PerfTestActivityRule mActivityRule = new PerfTestActivityRule();
+
+    /**
+     * IMF common methods to log for show/hide in trace.
+     */
+    private String[] mCommonMethods = {
+            "IC.pendingAnim",
+            "IMMS.applyImeVisibility",
+            "applyPostLayoutPolicy",
+            "applyWindowSurfaceChanges",
+            "ISC.onPostLayout"
+    };
+
+    /** IMF show methods to log in trace. */
+    private String[] mShowMethods = {
+            "IC.showRequestFromIme",
+            "IC.showRequestFromApi",
+            "IC.showRequestFromApiToImeReady",
+            "IC.pendingAnim",
+            "IMMS.applyImeVisibility",
+            "IMMS.showMySoftInput",
+            "IMMS.showSoftInput",
+            "IMS.showSoftInput",
+            "IMS.startInput",
+            "WMS.showImePostLayout",
+            "IMS.updateFullscreenMode",
+            "IMS.onComputeInsets",
+            "IMS.showWindow"
+    };
+
+    /** IMF show methods to log in trace. */
+    private String[] mShowMethodsCold = {
+            "IMS.bindInput",
+            "IMS.initializeInternal",
+            "IMS.restartInput",
+            "IMS.onCreate",
+            "IMS.initSoftInputWindow",
+            "IMS.resetStateForNewConfiguration",
+            "IMMS.onServiceConnected",
+            "IMMS.sessionCreated",
+            "IMMS.startInputOrWindowGainedFocus"
+    };
+
+    /** IMF hide lifecycle methods to log in trace. */
+    private String[] mHideMethods = {
+            "IC.hideRequestFromIme",
+            "IC.hideRequestFromApi",
+            "IMMS.hideMySoftInput",
+            "IMMS.hideSoftInput",
+            "IMS.hideSoftInput",
+            "WMS.hideIme"
+    };
+
+    /**
+     * IMF methods to log in trace.
+     */
+    private TraceMarkParser mTraceMethods;
+
+    private boolean mIsTraceStarted;
+
+    /**
+     * Ime Session for {@link BaselineIme}.
+     */
+    private static class ImeSession implements AutoCloseable {
+
+        private static final long TIMEOUT = 2000;
+        private final ComponentName mImeName;
+        private Context mContext = getInstrumentation().getContext();
+
+        ImeSession(ComponentName ime) throws Exception {
+            mImeName = ime;
+            // using adb, enable and set Baseline IME.
+            executeShellCommand("ime reset");
+            executeShellCommand("ime enable " + ime.flattenToShortString());
+            executeShellCommand("ime set " + ime.flattenToShortString());
+            PollingCheck.check("Make sure that BaselineIme becomes available "
+                    + getCurrentInputMethodId(), TIMEOUT,
+                    () -> ime.equals(getCurrentInputMethodId()));
+        }
+
+        @Override
+        public void close() throws Exception {
+            executeShellCommand("ime reset");
+            PollingCheck.check("Make sure that Baseline IME becomes unavailable", TIMEOUT, () ->
+                    mContext.getSystemService(InputMethodManager.class)
+                            .getEnabledInputMethodList()
+                            .stream()
+                            .noneMatch(info -> mImeName.equals(info.getComponent())));
+        }
+
+        @Nullable
+        private ComponentName getCurrentInputMethodId() {
+            return ComponentName.unflattenFromString(
+                    Settings.Secure.getString(mContext.getContentResolver(),
+                            Settings.Secure.DEFAULT_INPUT_METHOD));
+        }
+    }
+
+    /**
+     * A minimal baseline IME (that has a single static view) used to measure IMF latency.
+     */
+    public static class BaselineIme extends InputMethodService {
+
+        public static final int HEIGHT_DP = 100;
+        private static int sPid;
+
+        @Override
+        public View onCreateInputView() {
+            final ViewGroup view = new FrameLayout(this);
+            final View inner = new View(this);
+            final float density = getResources().getDisplayMetrics().density;
+            final int height = (int) (HEIGHT_DP * density);
+            view.setPadding(0, 0, 0, 0);
+            view.addView(inner, new FrameLayout.LayoutParams(MATCH_PARENT, height));
+            inner.setBackgroundColor(0xff01fe10); // green
+            sPid = Process.myPid();
+            return view;
+        }
+
+        static int getPid() {
+            return sPid;
+        }
+
+        static ComponentName getName(Context context) {
+            return new ComponentName(context, BaselineIme.class);
+        }
+    }
+
+    @Test
+    @ManualBenchmarkTest(
+            targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+            statsReport = @StatsReport(
+                    flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+                            | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+                            | StatsReport.FLAG_COEFFICIENT_VAR))
+    public void testShowImeWarm() throws Throwable {
+        testShowOrHideImeWarm(true /* show */);
+    }
+
+    @Test
+    @ManualBenchmarkTest(
+            targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+            statsReport = @StatsReport(
+                    flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+                            | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+                            | StatsReport.FLAG_COEFFICIENT_VAR))
+    public void testHideIme() throws Throwable {
+        testShowOrHideImeWarm(false /* show */);
+    }
+
+    @Test
+    @ManualBenchmarkTest(
+            targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+            statsReport = @StatsReport(
+                    flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+                            | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+                            | StatsReport.FLAG_COEFFICIENT_VAR))
+    public void testShowImeCold() throws Throwable {
+        mTraceMethods = new TraceMarkParser(
+                buildArray(mCommonMethods, mShowMethods, mShowMethodsCold));
+
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
+        if (state.isWarmingUp()) {
+            // we don't need to warmup for cold start.
+            return;
+        }
+
+        long measuredTimeNs = 0;
+        while (state.keepRunning(measuredTimeNs)) {
+            killBaselineIme();
+            try (ImeSession imeSession = new ImeSession(BaselineIme.getName(
+                    getInstrumentation().getContext()))) {
+                final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>();
+                final Activity activity = getActivityWithFocus();
+
+                setImeListener(activity, latchStart, null /* latchEnd */);
+                latchStart.set(new CountDownLatch(1));
+
+                if (!mIsTraceStarted) {
+                    startAsyncAtrace();
+                }
+
+                final WindowInsetsController controller =
+                        activity.getWindow().getDecorView().getWindowInsetsController();
+                AtomicLong startTime = new AtomicLong();
+                activity.runOnUiThread(() -> {
+                    startTime.set(SystemClock.elapsedRealtimeNanos());
+                    controller.show(WindowInsets.Type.ime());
+                });
+
+                measuredTimeNs = waitForAnimationStart(latchStart, startTime);
+                mActivityRule.finishActivity();
+            }
+        }
+        stopAsyncAtrace();
+        addResultToState(state);
+    }
+
+    private void killBaselineIme() {
+        assertTrue("PID of test and IME can't be same",
+                Process.myPid() != BaselineIme.getPid());
+        Process.killProcess(BaselineIme.getPid());
+    }
+
+    private void testShowOrHideImeWarm(final boolean show) throws Throwable {
+        mTraceMethods = new TraceMarkParser(buildArray(
+                mCommonMethods, show ? mShowMethods : mHideMethods));
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
+        long measuredTimeNs = 0;
+        try (ImeSession imeSession = new ImeSession(BaselineIme.getName(
+                getInstrumentation().getContext()))) {
+            final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>();
+            final AtomicReference<CountDownLatch> latchEnd = new AtomicReference<>();
+            final Activity activity = getActivityWithFocus();
+
+            // call IME show/hide
+            final WindowInsetsController controller =
+                    activity.getWindow().getDecorView().getWindowInsetsController();
+
+            while (state.keepRunning(measuredTimeNs)) {
+                setImeListener(activity, latchStart, latchEnd);
+                // For measuring hide, lets show IME first.
+                if (!show) {
+                    initLatch(latchStart, latchEnd);
+                    AtomicBoolean showCalled = new AtomicBoolean();
+                    getInstrumentation().runOnMainSync(() -> {
+                        if (!isImeVisible(activity)) {
+                            controller.show(WindowInsets.Type.ime());
+                            showCalled.set(true);
+                        }
+                    });
+                    if (showCalled.get()) {
+                        PollingCheck.check("IME show animation should finish ",
+                                TIMEOUT_1_S_IN_MS * 3,
+                                () -> latchStart.get().getCount() == 0
+                                        && latchEnd.get().getCount() == 0);
+                    }
+                }
+                if (!mIsTraceStarted && !state.isWarmingUp()) {
+                    startAsyncAtrace();
+                    mIsTraceStarted = true;
+                }
+
+                AtomicLong startTime = new AtomicLong();
+                AtomicBoolean unexpectedVisibility = new AtomicBoolean();
+                initLatch(latchStart, latchEnd);
+                getInstrumentation().runOnMainSync(() -> {
+                    boolean isVisible = isImeVisible(activity);
+                    startTime.set(SystemClock.elapsedRealtimeNanos());
+
+                    if (show && !isVisible) {
+                        controller.show(WindowInsets.Type.ime());
+                    } else if (!show && isVisible) {
+                        controller.hide(WindowInsets.Type.ime());
+                    } else {
+                        // ignore this iteration as unexpected IME visibility was encountered.
+                        unexpectedVisibility.set(true);
+                    }
+                });
+
+                if (!unexpectedVisibility.get()) {
+                    long timeElapsed = waitForAnimationStart(latchStart, startTime);
+                    if (timeElapsed != ANIMATION_NOT_STARTED) {
+                        measuredTimeNs = timeElapsed;
+                        // wait for animation to end or we may start two animations and timing
+                        // will not be measured accurately.
+                        waitForAnimationEnd(latchEnd);
+                    }
+                }
+
+                // hide IME before next iteration.
+                if (show) {
+                    initLatch(latchStart, latchEnd);
+                    activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime()));
+                    try {
+                        latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
+                        if (latchEnd.get().getCount() != 0
+                                && getOnMainSync(() -> isImeVisible(activity))) {
+                            Assert.fail("IME hide animation should finish.");
+                        }
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        } finally {
+            if (mIsTraceStarted) {
+                stopAsyncAtrace();
+            }
+        }
+        mActivityRule.finishActivity();
+
+        addResultToState(state);
+    }
+
+    private void initLatch(AtomicReference<CountDownLatch> latchStart,
+            AtomicReference<CountDownLatch> latchEnd) {
+        latchStart.set(new CountDownLatch(1));
+        latchEnd.set(new CountDownLatch(1));
+    }
+
+    @UiThread
+    private boolean isImeVisible(@NonNull final Activity activity) {
+        return activity.getWindow().getDecorView().getRootWindowInsets().isVisible(
+                WindowInsets.Type.ime());
+    }
+
+    private long waitForAnimationStart(
+            AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) {
+        try {
+            latchStart.get().await(5, TimeUnit.SECONDS);
+            if (latchStart.get().getCount() != 0) {
+                return ANIMATION_NOT_STARTED;
+            }
+        } catch (InterruptedException e) { }
+
+        return SystemClock.elapsedRealtimeNanos() - startTime.get();
+    }
+
+    private void waitForAnimationEnd(AtomicReference<CountDownLatch> latchEnd) {
+        try {
+            latchEnd.get().await(3, TimeUnit.SECONDS);
+        } catch (InterruptedException e) { }
+    }
+
+    private void addResultToState(ManualBenchmarkState state) {
+        mTraceMethods.forAllSlices((key, slices) -> {
+            for (TraceMarkSlice slice : slices) {
+                state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
+            }
+        });
+        Log.i(TAG, String.valueOf(mTraceMethods));
+    }
+
+    private Activity getActivityWithFocus() throws Exception {
+        final Activity activity = mActivityRule.launchActivity();
+        PollingCheck.check("Activity onResume()", TIMEOUT_1_S_IN_MS,
+                () -> activity.isResumed());
+
+        View editor = activity.findViewById(ID_EDITOR);
+        editor.requestFocus();
+
+        // wait till editor is focused so we don't count activity/view latency.
+        PollingCheck.check("Editor is focused", TIMEOUT_1_S_IN_MS,
+                () -> editor.isFocused());
+        getInstrumentation().waitForIdleSync();
+
+        return activity;
+    }
+
+    private void setImeListener(Activity activity,
+            @NonNull AtomicReference<CountDownLatch> latchStart,
+            @Nullable AtomicReference<CountDownLatch> latchEnd) {
+        // set IME animation listener
+        activity.getWindow().getDecorView().setWindowInsetsAnimationCallback(
+                new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
+                    @NonNull
+                    @Override
+                    public WindowInsetsAnimation.Bounds onStart(
+                            @NonNull WindowInsetsAnimation animation,
+                            @NonNull WindowInsetsAnimation.Bounds bounds) {
+                        latchStart.get().countDown();
+                        return super.onStart(animation, bounds);
+                    }
+
+                    @NonNull
+                    @Override
+                    public WindowInsets onProgress(@NonNull WindowInsets insets,
+                            @NonNull List<WindowInsetsAnimation> runningAnimations) {
+                        return insets;
+                    }
+
+                    @Override
+                    public void onEnd(@NonNull WindowInsetsAnimation animation) {
+                        super.onEnd(animation);
+                        if (latchEnd != null) {
+                            latchEnd.get().countDown();
+                        }
+                    }
+                });
+    }
+
+    private void startAsyncAtrace() {
+        mIsTraceStarted = true;
+        // IMF uses 'wm' component for trace in InputMethodService, InputMethodManagerService,
+        // WindowManagerService and 'view' for client window (InsetsController).
+        // TODO(b/167947940): Consider a separate input_method atrace
+        startAsyncAtrace("wm view");
+    }
+
+    private void stopAsyncAtrace() {
+        if (!mIsTraceStarted) {
+            return;
+        }
+        mIsTraceStarted = false;
+        final InputStream inputStream = stopAsyncAtraceWithStream();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                mTraceMethods.visit(line);
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to read the result of stopped atrace", e);
+        }
+    }
+
+    @Override
+    public void onStart(int iteration) {
+        // Do not capture trace when profiling because the result will be much slower.
+        stopAsyncAtrace();
+    }
+
+    @Override
+    public void onFinished(int iteration) {
+        // do nothing.
+    }
+}
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
new file mode 100644
index 0000000..f70d79c
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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.inputmethod;
+
+import static android.perftests.utils.PerfTestActivity.INTENT_EXTRA_ADD_EDIT_TEXT;
+
+import android.content.Intent;
+import android.perftests.utils.PerfTestActivity;
+import android.perftests.utils.WindowPerfTestBase;
+
+public class ImePerfTestBase extends WindowPerfTestBase {
+    static final long TIMEOUT_1_S_IN_MS = 1 * 1000L;
+
+    /** Provides an activity that contains an edit text view.*/
+    static class PerfTestActivityRule extends PerfTestActivityRuleBase {
+
+        @Override
+        public PerfTestActivity launchActivity(Intent intent) {
+            intent.putExtra(INTENT_EXTRA_ADD_EDIT_TEXT, true);
+            return super.launchActivity(intent);
+        }
+    }
+
+    static String[] buildArray(String[]... arrays) {
+        int length = 0;
+        for (String[] array : arrays) {
+            length += array.length;
+        }
+        String[] newArray = new String[length];
+        int offset = 0;
+        for (String[] array : arrays) {
+            System.arraycopy(array, 0, newArray, offset, array.length);
+            offset += array.length;
+        }
+        return newArray;
+    }
+}
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 04432f2..c967e51 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "MultiUserPerfTests",
     srcs: ["src/**/*.java"],
@@ -22,5 +31,6 @@
     ],
     platform_apis: true,
     test_suites: ["device-tests"],
+    data: ["trace_configs/*"],
     certificate: "platform",
 }
diff --git a/apct-tests/perftests/multiuser/AndroidManifest.xml b/apct-tests/perftests/multiuser/AndroidManifest.xml
index e4196dd..63e5983 100644
--- a/apct-tests/perftests/multiuser/AndroidManifest.xml
+++ b/apct-tests/perftests/multiuser/AndroidManifest.xml
@@ -17,16 +17,16 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.perftests.multiuser">
 
-    <uses-sdk android:targetSdkVersion="28" />
 
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
     <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" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <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 9117561..8e342f3 100644
--- a/apct-tests/perftests/multiuser/AndroidTest.xml
+++ b/apct-tests/perftests/multiuser/AndroidTest.xml
@@ -16,14 +16,51 @@
 <configuration description="Runs MultiUserPerfTests metric instrumentation.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-metric-instrumentation" />
+
     <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>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_multi_user.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+        <!--Install the content provider automatically when we push some file in sdcard folder.-->
+        <!--Needed to avoid the installation during the test suite.-->
+        <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.multiuser" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
     </test>
 </configuration>
diff --git a/apct-tests/perftests/multiuser/OWNERS b/apct-tests/perftests/multiuser/OWNERS
new file mode 100644
index 0000000..1a206cb
--- /dev/null
+++ b/apct-tests/perftests/multiuser/OWNERS
@@ -0,0 +1 @@
+include /MULTIUSER_OWNERS
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
index 08c54a6..892c140 100644
--- a/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
+++ b/apct-tests/perftests/multiuser/apps/dummyapp/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test_helper_app {
     name: "MultiUserPerfDummyApp",
 
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
index c1362dc..cd3c11c 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
@@ -22,6 +22,9 @@
 import java.util.concurrent.TimeUnit;
 
 public class BenchmarkResults {
+    /** If the test fails, output this value as a signal of the failure. */
+    public static final long DECLARED_VALUE_IF_ERROR_MS = -10;
+
     private final ArrayList<Long> mResults = new ArrayList<>();
 
     public void addDuration(long duration) {
@@ -42,6 +45,28 @@
         return stats;
     }
 
+    /**
+     * Same as {@link #getStatsToReport()} but for failure,
+     * using {@link #DECLARED_VALUE_IF_ERROR_MS}.
+     */
+    public static Bundle getFailedStatsToReport() {
+        final Bundle stats = new Bundle();
+        stats.putDouble("Mean (ms)", DECLARED_VALUE_IF_ERROR_MS);
+        return stats;
+    }
+
+    /**
+     * Same as {@link #getStatsToLog()} but for failure,
+     * using {@link #DECLARED_VALUE_IF_ERROR_MS}.
+     */
+    public static Bundle getFailedStatsToLog() {
+        final Bundle stats = new Bundle();
+        stats.putDouble("Mean (ms)", DECLARED_VALUE_IF_ERROR_MS);
+        stats.putDouble("Median (ms)", DECLARED_VALUE_IF_ERROR_MS);
+        stats.putDouble("Sigma (ms)", DECLARED_VALUE_IF_ERROR_MS);
+        return stats;
+    }
+
     public ArrayList<Long> getAllDurations() {
         return mResults;
     }
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java
index ba33e64..b6f13fd 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResultsReporter.java
@@ -15,6 +15,8 @@
  */
 package android.multiuser;
 
+import static android.multiuser.BenchmarkResults.DECLARED_VALUE_IF_ERROR_MS;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.Bundle;
@@ -40,28 +42,70 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                base.evaluate();
-                final Bundle stats = mRunner.getStatsToReport();
-                final String summary = getSummaryString(description.getMethodName(),
-                        mRunner.getStatsToLog());
-                logSummary(description.getTestClass().getSimpleName(), summary,
-                        mRunner.getAllDurations());
-                stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, summary);
-                InstrumentationRegistry.getInstrumentation().sendStatus(
-                        Activity.RESULT_OK, stats);
+                final String tag = description.getTestClass().getSimpleName();
+                final String methodName = description.getMethodName();
+                Throwable error = null;
+
+                try {
+                    base.evaluate();
+                    error = mRunner.getErrorOrNull();
+                } catch (Exception e) {
+                    error = e;
+                }
+
+                if (error != null) {
+                    Log.e(tag, "Test " + methodName + " failed.", error);
+                    Log.d(tag, "Logcat displays the results ignoring the fact that it failed;\n"
+                            + "however, fake results of " + DECLARED_VALUE_IF_ERROR_MS + "ms "
+                            + "will be reported to the instrumentation caller to signify failure.");
+                }
+
+                final String summary = getSummaryString(methodName, mRunner.getStatsToLog());
+                logSummary(tag, summary, mRunner.getAllDurations());
+
+                Bundle stats;
+                if (error == null) {
+                    stats = mRunner.getStatsToReport();
+                    stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, summary);
+                } else {
+                    stats = BenchmarkResults.getFailedStatsToReport();
+                    final String failSummary = getSummaryString(methodName,
+                            BenchmarkResults.getFailedStatsToLog());
+                    stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, failSummary);
+                }
+                InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, stats);
+
+                if (error != null) {
+                    throw error;
+                }
             }
         };
     }
 
+    /**
+     * Prints, for example:
+     *  UserLifecycleTests: (summary string)
+     *  UserLifecycleTests: 1->101
+     *  UserLifecycleTests: 2->102
+     *  UserLifecycleTests: 3->103
+     *  UserLifecycleTests: 4->102
+     */
     private void logSummary(String tag, String summary, ArrayList<Long> durations) {
         final StringBuilder sb = new StringBuilder(summary);
         final int size = durations.size();
         for (int i = 0; i < size; ++i) {
-            sb.append("\n").append(i).append("->").append(durations.get(i));
+            sb.append("\n").append(i+1).append("->").append(durations.get(i));
         }
         Log.d(tag, sb.toString());
     }
 
+    /**
+     * For example:
+     *  testName
+     *  Sigma (ms): 1
+     *  Mean (ms): 2
+     *  Median (ms): 3
+     */
     private String getSummaryString(String testName, Bundle stats) {
         final StringBuilder sb = new StringBuilder();
         sb.append("\n\n").append(getKey(testName));
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
index 7b65bfa..8305d3f 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -15,6 +15,7 @@
  */
 package android.multiuser;
 
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.perftests.utils.ShellHelper;
@@ -35,12 +36,14 @@
 
     private final BenchmarkResults mResults = new BenchmarkResults();
     private int mState = NOT_STARTED;  // Current benchmark state.
-    private int mIteration;
+    private int mIteration = 1;
 
     public long mStartTimeNs;
     public long mPausedDurationNs;
     public long mPausedTimeNs;
 
+    private Throwable mFirstFailure = null;
+
     public boolean keepRunning() {
         switch (mState) {
             case NOT_STARTED:
@@ -61,7 +64,7 @@
 
     private boolean startNextTestRun() {
         mResults.addDuration(System.nanoTime() - mStartTimeNs - mPausedDurationNs);
-        if (mIteration == NUM_ITERATIONS) {
+        if (mIteration == NUM_ITERATIONS + 1) {
             mState = FINISHED;
             return false;
         } else {
@@ -104,4 +107,30 @@
     public ArrayList<Long> getAllDurations() {
         return mResults.getAllDurations();
     }
+
+    /** Returns which iteration (starting at 1) the Runner is currently on. */
+    public int getIteration() {
+        return mIteration;
+    }
+
+    /**
+     * Marks the test run as failed, along with a message of why.
+     * Only the first fail message is retained.
+     */
+    public void markAsFailed(Throwable err) {
+        if (mFirstFailure == null) {
+            mFirstFailure = err;
+        }
+    }
+
+    /** Gets the failure message if the test failed; otherwise {@code null}. */
+    public @Nullable Throwable getErrorOrNull() {
+        if (mFirstFailure != null) {
+            return mFirstFailure;
+        }
+        if (mState != FINISHED) {
+            return new AssertionError("BenchmarkRunner state is not FINISHED.");
+        }
+        return null;
+    }
 }
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index e042782..b1c42a9 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -17,6 +17,7 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -38,6 +39,7 @@
 import android.os.IBinder;
 import android.os.IProgressListener;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -62,7 +64,10 @@
 /**
  * Perf tests for user life cycle events.
  *
- * Running the tests:
+ * To run the tests: atest UserLifecycleTests
+ *
+ *
+ * Old methods for running the tests:
  *
  * make MultiUserPerfTests &&
  * adb install -r \
@@ -85,6 +90,10 @@
     private static final int TIMEOUT_IN_SECOND = 30;
     private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
 
+    /** Name of users/profiles in the test. Users with this name may be freely removed. */
+    private static final String TEST_USER_NAME = "UserLifecycleTests_test_user";
+
+    /** Name of dummy package used when timing how long app launches take. */
     private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp";
 
     // Copy of UserSystemPackageInstaller whitelist mode constants.
@@ -115,6 +124,11 @@
         mUsersToRemove = new ArrayList<>();
         mPm = context.getPackageManager();
         mHasManagedUserFeature = mPm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS);
+        removeAnyPreviousTestUsers();
+        if (mAm.getCurrentUser() != UserHandle.USER_SYSTEM) {
+            Log.w(TAG, "WARNING: Tests are being run from user " + mAm.getCurrentUser()
+                    + " rather than the system user");
+        }
     }
 
     @After
@@ -140,7 +154,7 @@
     }
 
     @Test
-    public void createAndStartUser() throws Exception {
+    public void createAndStartUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             final int userId = createUserNoFlags();
 
@@ -149,7 +163,7 @@
             // Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
             // ACTION_USER_STARTED.
             mIam.startUserInBackground(userId);
-            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
 
             mRunner.pauseTiming();
             removeUser(userId);
@@ -161,7 +175,7 @@
      * Measures the time until ACTION_USER_STARTED is received.
      */
     @Test
-    public void startUser() throws Exception {
+    public void startUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
@@ -170,7 +184,7 @@
             mRunner.resumeTiming();
 
             mIam.startUserInBackground(userId);
-            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
 
             mRunner.pauseTiming();
             removeUser(userId);
@@ -182,7 +196,7 @@
      * Measures the time until unlock listener is triggered and user is unlocked.
      */
     @Test
-    public void startAndUnlockUser() throws Exception {
+    public void startAndUnlockUser() {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
@@ -197,10 +211,8 @@
         }
     }
 
-
-
     @Test
-    public void switchUser() throws Exception {
+    public void switchUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
@@ -210,7 +222,7 @@
             switchUser(userId);
 
             mRunner.pauseTiming();
-            switchUser(startUser);
+            switchUserNoCheck(startUser);
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -218,7 +230,7 @@
 
     /** Tests switching to an already-created, but no-longer-running, user. */
     @Test
-    public void switchUser_stopped() throws Exception {
+    public void switchUser_stopped() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
@@ -228,11 +240,11 @@
             mRunner.resumeTiming();
 
             mAm.switchUser(testUser);
-            boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, latch);
+
 
             mRunner.pauseTiming();
-            attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success);
-            switchUser(startUser);
+            switchUserNoCheck(startUser);
             removeUser(testUser);
             mRunner.resumeTiming();
         }
@@ -240,7 +252,7 @@
 
     /** Tests switching to an already-created already-running non-owner user. */
     @Test
-    public void switchUser_running() throws Exception {
+    public void switchUser_running() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
@@ -250,22 +262,21 @@
             switchUser(testUser);
 
             mRunner.pauseTiming();
-            attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser));
-            switchUser(startUser);
+            switchUserNoCheck(startUser);
             removeUser(testUser);
             mRunner.resumeTiming();
         }
     }
 
     @Test
-    public void stopUser() throws Exception {
+    public void stopUser() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int userId = createUserNoFlags();
             final CountDownLatch latch = new CountDownLatch(1);
             registerBroadcastReceiver(Intent.ACTION_USER_STARTED, latch, userId);
             mIam.startUserInBackground(userId);
-            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve ACTION_USER_STARTED for user " + userId, latch);
             mRunner.resumeTiming();
 
             stopUser(userId, false);
@@ -277,7 +288,7 @@
     }
 
     @Test
-    public void lockedBootCompleted() throws Exception {
+    public void lockedBootCompleted() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
@@ -287,17 +298,17 @@
             mRunner.resumeTiming();
 
             mAm.switchUser(userId);
-            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve onLockedBootComplete for user " + userId, latch);
 
             mRunner.pauseTiming();
-            switchUser(startUser);
+            switchUserNoCheck(startUser);
             removeUser(userId);
             mRunner.resumeTiming();
         }
     }
 
     @Test
-    public void ephemeralUserStopped() throws Exception {
+    public void ephemeralUserStopped() throws RemoteException {
         while (mRunner.keepRunning()) {
             mRunner.pauseTiming();
             final int startUser = mAm.getCurrentUser();
@@ -318,10 +329,14 @@
             mRunner.resumeTiming();
 
             mAm.switchUser(startUser);
-            latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            waitForLatch("Failed to achieve ACTION_USER_STOPPED for user " + userId, latch);
 
             mRunner.pauseTiming();
-            switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            try {
+                switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Thread interrupted unexpectedly while waiting for switch.", e);
+            }
             removeUser(userId);
             mRunner.resumeTiming();
         }
@@ -329,7 +344,7 @@
 
     /** Tests creating a new profile. */
     @Test
-    public void managedProfileCreate() throws Exception {
+    public void managedProfileCreate() {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -344,7 +359,7 @@
 
     /** Tests starting (unlocking) a newly-created profile. */
     @Test
-    public void managedProfileUnlock() throws Exception {
+    public void managedProfileUnlock() {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -362,7 +377,7 @@
 
     /** Tests starting (unlocking) an already-created, but no-longer-running, profile. */
     @Test
-    public void managedProfileUnlock_stopped() throws Exception {
+    public void managedProfileUnlock_stopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -385,7 +400,7 @@
      * Tests starting (unlocking) and launching an already-installed app in a newly-created profile.
      */
     @Test
-    public void managedProfileUnlockAndLaunchApp() throws Exception {
+    public void managedProfileUnlockAndLaunchApp() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -411,7 +426,7 @@
      * {@link #managedProfileUnlock_stopped}}.
      */
     @Test
-    public void managedProfileUnlockAndLaunchApp_stopped() throws Exception {
+    public void managedProfileUnlockAndLaunchApp_stopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -422,7 +437,7 @@
             startUserInBackgroundAndWaitForUnlock(userId);
             startApp(userId, DUMMY_PACKAGE_NAME);
             stopUser(userId, true);
-            TimeUnit.SECONDS.sleep(1); // Brief cool-down before re-starting profile.
+            SystemClock.sleep(1_000); // 1 second cool-down before re-starting profile.
             mRunner.resumeTiming();
 
             startUserInBackgroundAndWaitForUnlock(userId);
@@ -436,7 +451,7 @@
 
     /** Tests installing a pre-existing app in a newly-created profile. */
     @Test
-    public void managedProfileInstall() throws Exception {
+    public void managedProfileInstall() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -457,7 +472,7 @@
      * and launching that app in it.
      */
     @Test
-    public void managedProfileCreateUnlockInstallAndLaunchApp() throws Exception {
+    public void managedProfileCreateUnlockInstallAndLaunchApp() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -478,7 +493,7 @@
 
     /** Tests stopping a profile. */
     @Test
-    public void managedProfileStopped() throws Exception {
+    public void managedProfileStopped() throws RemoteException {
         assumeTrue(mHasManagedUserFeature);
 
         while (mRunner.keepRunning()) {
@@ -498,7 +513,7 @@
     // 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 {
+    public void managedProfileUnlock_usingWhitelist() {
         assumeTrue(mHasManagedUserFeature);
         final int origMode = getUserTypePackageWhitelistMode();
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE
@@ -522,7 +537,7 @@
     }
     /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */
     @Test
-    public void managedProfileUnlock_notUsingWhitelist() throws Exception {
+    public void managedProfileUnlock_notUsingWhitelist() {
         assumeTrue(mHasManagedUserFeature);
         final int origMode = getUserTypePackageWhitelistMode();
         setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
@@ -551,19 +566,17 @@
 
     /** Creates a new user with the given flags, returning its userId. */
     private int createUserWithFlags(int flags) {
-        int userId = mUm.createUser("TestUser", flags).id;
+        int userId = mUm.createUser(TEST_USER_NAME, 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",
+        final UserInfo userInfo = mUm.createProfileForUser(TEST_USER_NAME,
                 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.");
-        }
+        attestFalse("Creating managed profile failed. Most likely there is "
+                + "already a pre-existing profile on the device.", userInfo == null);
         mUsersToRemove.add(userInfo.id);
         return userInfo.id;
     }
@@ -576,24 +589,40 @@
      */
     private void startUserInBackgroundAndWaitForUnlock(int userId) {
         final ProgressWaiter waiter = new ProgressWaiter();
+        boolean success = false;
         try {
             mIam.startUserInBackgroundWithListener(userId, waiter);
-            boolean success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
-            attestTrue("Failed to start user " + userId + " in background.", success);
+            success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
         } catch (RemoteException e) {
             Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e);
         }
+        attestTrue("Failed to start user " + userId + " in background.", success);
     }
 
     /** Starts the given user in the foreground. */
-    private void switchUser(int userId) throws Exception {
+    private void switchUser(int userId) throws RemoteException {
+        boolean success = switchUserNoCheck(userId);
+        attestTrue("Failed to properly switch to user " + userId, success);
+    }
+
+    /**
+     * Starts the given user in the foreground.
+     * Returns true if successful. Does not fail the test if unsuccessful.
+     * If lack of success should fail the test, use {@link #switchUser(int)} instead.
+     */
+    private boolean switchUserNoCheck(int userId) throws RemoteException {
         final CountDownLatch latch = new CountDownLatch(1);
         registerUserSwitchObserver(latch, null, userId);
         mAm.switchUser(userId);
-        latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+        try {
+            return latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Thread interrupted unexpectedly.", e);
+            return false;
+        }
     }
 
-    private void stopUser(int userId, boolean force) throws Exception {
+    private void stopUser(int userId, boolean force) throws RemoteException {
         final CountDownLatch latch = new CountDownLatch(1);
         mIam.stopUser(userId, force /* force */, new IStopUserCallback.Stub() {
             @Override
@@ -605,7 +634,7 @@
             public void userStopAborted(int userId) throws RemoteException {
             }
         });
-        latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+        waitForLatch("Failed to properly stop user " + userId, latch);
     }
 
     /**
@@ -615,15 +644,14 @@
      * @param stopNewUser whether to stop the new user after switching to otherUser.
      * @return userId of the newly created user.
      */
-    private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception {
+    private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws RemoteException {
         final int origUser = mAm.getCurrentUser();
         // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
         final int testUser = createUserNoFlags();
         final CountDownLatch latch1 = new CountDownLatch(1);
         registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
         mAm.switchUser(testUser);
-        attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser,
-                latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS));
+        waitForLatch("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser, latch1);
 
         // Second, switch back to origUser, waiting merely for switchUser() to finish
         switchUser(origUser);
@@ -656,11 +684,7 @@
                 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);
-        }
+        waitForLatch("Failed to install app " + packageName + " on user " + userId, latch);
     }
 
     /**
@@ -678,7 +702,7 @@
     }
 
     private void registerUserSwitchObserver(final CountDownLatch switchLatch,
-            final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
+            final CountDownLatch bootCompleteLatch, final int userId) throws RemoteException {
         ActivityManager.getService().registerUserSwitchObserver(
                 new UserSwitchObserver() {
                     @Override
@@ -734,6 +758,17 @@
         }
     }
 
+    /** Waits TIMEOUT_IN_SECOND for the latch to complete, otherwise declares the given error. */
+    private void waitForLatch(String errMsg, CountDownLatch latch) {
+        boolean success = false;
+        try {
+            success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Thread interrupted unexpectedly.", e);
+        }
+        attestTrue(errMsg, success);
+    }
+
     /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */
     private int getUserTypePackageWhitelistMode() {
         return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP,
@@ -767,13 +802,30 @@
         }
     }
 
-    private void attestTrue(String message, boolean assertion) {
-        if (!assertion) {
-            Log.w(TAG, message);
+    private void removeAnyPreviousTestUsers() {
+        for (UserInfo user : mUm.getUsers()) {
+            if (TEST_USER_NAME.equals(user.name)) {
+                Log.i(TAG, "Found previous test user " + user.id + ". Removing it.");
+                if (mAm.getCurrentUser() == user.id) {
+                    try {
+                        switchUserNoCheck(UserHandle.USER_SYSTEM);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to correctly switch to system user", e);
+                    }
+                }
+                mUm.removeUser(user.id);
+            }
         }
     }
 
-    private void attestFalse(String message, boolean assertion) {
+    private void attestTrue(@NonNull String message, boolean assertion) {
+        if (!assertion) {
+            Log.e(TAG, "Test failed on iteration #" + mRunner.getIteration() + ": " + message);
+            mRunner.markAsFailed(new AssertionError(message));
+        }
+    }
+
+    private void attestFalse(@NonNull String message, boolean assertion) {
         attestTrue(message, !assertion);
     }
 }
diff --git a/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
new file mode 100644
index 0000000..14a3f8f
--- /dev/null
+++ b/apct-tests/perftests/multiuser/trace_configs/trace_config_multi_user.textproto
@@ -0,0 +1,154 @@
+# Copyright (C) 2021 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.
+
+# proto-message: TraceConfig
+
+# Enable periodic flushing of the trace buffer into the output file.
+write_into_file: true
+
+# Writes the userspace buffer into the file every 1s.
+file_write_period_ms: 1000
+
+# See b/126487238 - we need to guarantee ordering of events.
+flush_period_ms: 10000
+
+# The trace buffers needs to be big enough to hold |file_write_period_ms| of
+# trace data. The trace buffer sizing depends on the number of trace categories
+# enabled and the device activity.
+
+# RSS events
+buffers {
+  size_kb: 32768
+  fill_policy: RING_BUFFER
+}
+
+# procfs polling
+buffers {
+  size_kb: 8192
+  fill_policy: RING_BUFFER
+}
+
+data_sources {
+  config {
+    name: "linux.ftrace"
+    target_buffer: 0
+    ftrace_config {
+      # These parameters affect only the kernel trace buffer size and how
+      # frequently it gets moved into the userspace buffer defined above.
+      buffer_size_kb: 16384
+      drain_period_ms: 250
+
+      # Store certain high-volume "sched" ftrace events in a denser format
+      # (falling back to the default format if not supported by the tracer).
+      compact_sched {
+        enabled: true
+      }
+
+      # Enables symbol name resolution against /proc/kallsyms
+      symbolize_ksyms: true
+
+      # We need to do process tracking to ensure kernel ftrace events targeted at short-lived
+      # threads are associated correctly
+      ftrace_events: "task/task_newtask"
+      ftrace_events: "task/task_rename"
+      ftrace_events: "sched/sched_process_exit"
+      ftrace_events: "sched/sched_process_free"
+
+      # Memory events
+      ftrace_events: "rss_stat"
+      ftrace_events: "ion_heap_shrink"
+      ftrace_events: "ion_heap_grow"
+      ftrace_events: "ion/ion_stat"
+      ftrace_events: "dmabuf_heap/dma_heap_stat"
+      ftrace_events: "oom_score_adj_update"
+      ftrace_events: "gpu_mem/gpu_mem_total"
+
+      # Old (kernel) LMK
+      ftrace_events: "lowmemorykiller/lowmemory_kill"
+
+      atrace_apps: "*"
+
+      atrace_categories: "am"
+      atrace_categories: "bionic"
+      atrace_categories: "camera"
+      atrace_categories: "wm"
+      atrace_categories: "dalvik"
+      atrace_categories: "sched"
+      atrace_categories: "freq"
+      atrace_categories: "gfx"
+      atrace_categories: "view"
+      atrace_categories: "webview"
+      atrace_categories: "input"
+      atrace_categories: "hal"
+      atrace_categories: "binder_driver"
+      atrace_categories: "sync"
+      atrace_categories: "workq"
+      atrace_categories: "res"
+
+    }
+  }
+}
+
+data_sources: {
+  config {
+    name: "android.gpu.memory"
+    target_buffer: 0
+  }
+}
+
+data_sources {
+  config {
+    name: "linux.process_stats"
+    target_buffer: 1
+    process_stats_config {
+      proc_stats_poll_ms: 10000
+    }
+  }
+}
+
+data_sources {
+  config {
+    name: "linux.sys_stats"
+    target_buffer: 1
+    sys_stats_config {
+      meminfo_period_ms: 1000
+      meminfo_counters: MEMINFO_MEM_TOTAL
+      meminfo_counters: MEMINFO_MEM_FREE
+      meminfo_counters: MEMINFO_MEM_AVAILABLE
+      meminfo_counters: MEMINFO_BUFFERS
+      meminfo_counters: MEMINFO_CACHED
+      meminfo_counters: MEMINFO_SWAP_CACHED
+      meminfo_counters: MEMINFO_ACTIVE
+      meminfo_counters: MEMINFO_INACTIVE
+      meminfo_counters: MEMINFO_ACTIVE_ANON
+      meminfo_counters: MEMINFO_INACTIVE_ANON
+      meminfo_counters: MEMINFO_ACTIVE_FILE
+      meminfo_counters: MEMINFO_INACTIVE_FILE
+      meminfo_counters: MEMINFO_UNEVICTABLE
+      meminfo_counters: MEMINFO_SWAP_TOTAL
+      meminfo_counters: MEMINFO_SWAP_FREE
+      meminfo_counters: MEMINFO_DIRTY
+      meminfo_counters: MEMINFO_WRITEBACK
+      meminfo_counters: MEMINFO_ANON_PAGES
+      meminfo_counters: MEMINFO_MAPPED
+      meminfo_counters: MEMINFO_SHMEM
+    }
+  }
+}
+
+data_sources: {
+  config: {
+    name: "android.surfaceflinger.frametimeline"
+  }
+}
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index 17033e0..0e76488 100644
--- a/apct-tests/perftests/packagemanager/Android.bp
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "PackageManagerPerfTests",
 
@@ -10,6 +19,7 @@
         "androidx.test.ext.junit",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
+        "collector-device-lib-platform",
     ],
 
     libs: ["android.test.base"],
@@ -18,4 +28,8 @@
 
     test_suites: ["device-tests"],
 
+    data: [":perfetto_artifacts"],
+
+    certificate: "platform",
+
 }
diff --git a/apct-tests/perftests/packagemanager/AndroidManifest.xml b/apct-tests/perftests/packagemanager/AndroidManifest.xml
index 520f4b5..4bcd557 100644
--- a/apct-tests/perftests/packagemanager/AndroidManifest.xml
+++ b/apct-tests/perftests/packagemanager/AndroidManifest.xml
@@ -76,7 +76,8 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
-        <activity android:name="android.perftests.utils.PerfTestActivity">
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
           <intent-filter>
             <action android:name="com.android.perftests.packagemanager.PERFTEST" />
           </intent-filter>
diff --git a/apct-tests/perftests/packagemanager/AndroidTest.xml b/apct-tests/perftests/packagemanager/AndroidTest.xml
index c112d87..4903510 100644
--- a/apct-tests/perftests/packagemanager/AndroidTest.xml
+++ b/apct-tests/perftests/packagemanager/AndroidTest.xml
@@ -15,74 +15,122 @@
   ~ limitations under the License.
   -->
 <configuration description="Runs PackageManagerPerfTests metric instrumentation.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <option name="test-suite-tag" value="apct"/>
+    <option name="test-suite-tag" value="apct-metric-instrumentation"/>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="PackageManagerPerfTests.apk" />
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="PackageManagerPerfTests.apk"/>
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true" />
-        <option name="force-queryable" value="false" />
-        <option name="test-file-name" value="QueriesAll0.apk" />
-        <option name="test-file-name" value="QueriesAll1.apk" />
-        <option name="test-file-name" value="QueriesAll2.apk" />
-        <option name="test-file-name" value="QueriesAll3.apk" />
-        <option name="test-file-name" value="QueriesAll4.apk" />
-        <option name="test-file-name" value="QueriesAll5.apk" />
-        <option name="test-file-name" value="QueriesAll6.apk" />
-        <option name="test-file-name" value="QueriesAll7.apk" />
-        <option name="test-file-name" value="QueriesAll8.apk" />
-        <option name="test-file-name" value="QueriesAll9.apk" />
-        <option name="test-file-name" value="QueriesAll10.apk" />
-        <option name="test-file-name" value="QueriesAll11.apk" />
-        <option name="test-file-name" value="QueriesAll12.apk" />
-        <option name="test-file-name" value="QueriesAll13.apk" />
-        <option name="test-file-name" value="QueriesAll14.apk" />
-        <option name="test-file-name" value="QueriesAll15.apk" />
-        <option name="test-file-name" value="QueriesAll16.apk" />
-        <option name="test-file-name" value="QueriesAll17.apk" />
-        <option name="test-file-name" value="QueriesAll18.apk" />
-        <option name="test-file-name" value="QueriesAll19.apk" />
-        <option name="test-file-name" value="QueriesAll20.apk" />
-        <option name="test-file-name" value="QueriesAll21.apk" />
-        <option name="test-file-name" value="QueriesAll22.apk" />
-        <option name="test-file-name" value="QueriesAll23.apk" />
-        <option name="test-file-name" value="QueriesAll24.apk" />
-        <option name="test-file-name" value="QueriesAll25.apk" />
-        <option name="test-file-name" value="QueriesAll26.apk" />
-        <option name="test-file-name" value="QueriesAll27.apk" />
-        <option name="test-file-name" value="QueriesAll28.apk" />
-        <option name="test-file-name" value="QueriesAll29.apk" />
-        <option name="test-file-name" value="QueriesAll30.apk" />
-        <option name="test-file-name" value="QueriesAll31.apk" />
-        <option name="test-file-name" value="QueriesAll32.apk" />
-        <option name="test-file-name" value="QueriesAll33.apk" />
-        <option name="test-file-name" value="QueriesAll34.apk" />
-        <option name="test-file-name" value="QueriesAll35.apk" />
-        <option name="test-file-name" value="QueriesAll36.apk" />
-        <option name="test-file-name" value="QueriesAll37.apk" />
-        <option name="test-file-name" value="QueriesAll38.apk" />
-        <option name="test-file-name" value="QueriesAll39.apk" />
-        <option name="test-file-name" value="QueriesAll40.apk" />
-        <option name="test-file-name" value="QueriesAll41.apk" />
-        <option name="test-file-name" value="QueriesAll42.apk" />
-        <option name="test-file-name" value="QueriesAll43.apk" />
-        <option name="test-file-name" value="QueriesAll44.apk" />
-        <option name="test-file-name" value="QueriesAll45.apk" />
-        <option name="test-file-name" value="QueriesAll46.apk" />
-        <option name="test-file-name" value="QueriesAll47.apk" />
-        <option name="test-file-name" value="QueriesAll48.apk" />
-        <option name="test-file-name" value="QueriesAll49.apk" />
+        <option name="cleanup-apks" value="true"/>
+        <option name="force-queryable" value="false"/>
+        <option name="test-file-name" value="QueriesAll0.apk"/>
+        <option name="test-file-name" value="QueriesAll1.apk"/>
+        <option name="test-file-name" value="QueriesAll2.apk"/>
+        <option name="test-file-name" value="QueriesAll3.apk"/>
+        <option name="test-file-name" value="QueriesAll4.apk"/>
+        <option name="test-file-name" value="QueriesAll5.apk"/>
+        <option name="test-file-name" value="QueriesAll6.apk"/>
+        <option name="test-file-name" value="QueriesAll7.apk"/>
+        <option name="test-file-name" value="QueriesAll8.apk"/>
+        <option name="test-file-name" value="QueriesAll9.apk"/>
+        <option name="test-file-name" value="QueriesAll10.apk"/>
+        <option name="test-file-name" value="QueriesAll11.apk"/>
+        <option name="test-file-name" value="QueriesAll12.apk"/>
+        <option name="test-file-name" value="QueriesAll13.apk"/>
+        <option name="test-file-name" value="QueriesAll14.apk"/>
+        <option name="test-file-name" value="QueriesAll15.apk"/>
+        <option name="test-file-name" value="QueriesAll16.apk"/>
+        <option name="test-file-name" value="QueriesAll17.apk"/>
+        <option name="test-file-name" value="QueriesAll18.apk"/>
+        <option name="test-file-name" value="QueriesAll19.apk"/>
+        <option name="test-file-name" value="QueriesAll20.apk"/>
+        <option name="test-file-name" value="QueriesAll21.apk"/>
+        <option name="test-file-name" value="QueriesAll22.apk"/>
+        <option name="test-file-name" value="QueriesAll23.apk"/>
+        <option name="test-file-name" value="QueriesAll24.apk"/>
+        <option name="test-file-name" value="QueriesAll25.apk"/>
+        <option name="test-file-name" value="QueriesAll26.apk"/>
+        <option name="test-file-name" value="QueriesAll27.apk"/>
+        <option name="test-file-name" value="QueriesAll28.apk"/>
+        <option name="test-file-name" value="QueriesAll29.apk"/>
+        <option name="test-file-name" value="QueriesAll30.apk"/>
+        <option name="test-file-name" value="QueriesAll31.apk"/>
+        <option name="test-file-name" value="QueriesAll32.apk"/>
+        <option name="test-file-name" value="QueriesAll33.apk"/>
+        <option name="test-file-name" value="QueriesAll34.apk"/>
+        <option name="test-file-name" value="QueriesAll35.apk"/>
+        <option name="test-file-name" value="QueriesAll36.apk"/>
+        <option name="test-file-name" value="QueriesAll37.apk"/>
+        <option name="test-file-name" value="QueriesAll38.apk"/>
+        <option name="test-file-name" value="QueriesAll39.apk"/>
+        <option name="test-file-name" value="QueriesAll40.apk"/>
+        <option name="test-file-name" value="QueriesAll41.apk"/>
+        <option name="test-file-name" value="QueriesAll42.apk"/>
+        <option name="test-file-name" value="QueriesAll43.apk"/>
+        <option name="test-file-name" value="QueriesAll44.apk"/>
+        <option name="test-file-name" value="QueriesAll45.apk"/>
+        <option name="test-file-name" value="QueriesAll46.apk"/>
+        <option name="test-file-name" value="QueriesAll47.apk"/>
+        <option name="test-file-name" value="QueriesAll48.apk"/>
+        <option name="test-file-name" value="QueriesAll49.apk"/>
     </target_preparer>
 
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.perftests.packagemanager" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.perftests.packagemanager"/>
         <option name="hidden-api-checks" value="false"/>
     </test>
 
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/data/local/PackageManagerPerfTests" />
-        <option name="collect-on-run-ended-only" value="true" />
+        <option name="directory-keys" value="/data/local/PackageManagerPerfTests"/>
+        <option name="collect-on-run-ended-only" value="true"/>
     </metrics_collector>
+
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto"
+                value="/data/misc/perfetto-traces/trace_config.textproto"/>
+        <!--Install the content provider automatically when we push some file in sdcard folder.-->
+        <!--Needed to avoid the installation during the test suite.-->
+        <option name="push-file" key="trace_config_detailed.textproto"
+                value="/sdcard/sample.textproto"/>
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path"/>
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results -->
+    <option name="isolated-storage" value="false"/>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.perftests.packagemanager"/>
+        <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to
+             stabilize. -->
+        <option name="device-listeners"
+                value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener"/>
+        <!-- Guarantee that user defined RunListeners will be running before any of the default
+             listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true"/>
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting
+             the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true"/>
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3"/>
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000"/>
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000"/>
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
+        <option name="instrumentation-arg" key="perfetto_config_file"
+                value="trace_config.textproto"/>
+
+    </test>
+
+
 </configuration>
diff --git a/apct-tests/perftests/packagemanager/OWNERS b/apct-tests/perftests/packagemanager/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
index 3cb1589..b2339d5 100644
--- a/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
+++ b/apct-tests/perftests/packagemanager/apps/query-all/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test_helper_app {
     name: "QueriesAll0",
     aaptflags: [
diff --git a/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml
index e2cfa04..977c1dc 100644
--- a/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml
+++ b/apct-tests/perftests/packagemanager/apps/query-all/AndroidManifest.xml
@@ -18,7 +18,8 @@
           package="com.android.perftests.appenumeration">
 
     <application android:hasCode="false" >
-        <activity android:name="android.perftests.utils.PerfTestActivity">
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
             <intent-filter>
                 <action android:name="com.android.perftests.packagemanager.PERFTEST" />
             </intent-filter>
@@ -78,4 +79,4 @@
         <package android:name="com.android.perftests.appenumeration49" />
     </queries>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 49952dc..1011267 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "TextClassifierPerfTests",
     srcs: ["src/**/*.java"],
@@ -19,7 +28,9 @@
         "androidx.test.rules",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
+        "collector-device-lib",
     ],
+    data: [":perfetto_artifacts"],
     platform_apis: true,
     test_suites: ["device-tests"],
 }
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 3df51b8..3fac462 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -21,8 +21,40 @@
         <option name="test-file-name" value="TextClassifierPerfTests.apk" />
     </target_preparer>
 
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for pulling the collected trace config on to the host -->
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
+    </metrics_collector>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.textclassifier" />
         <option name="hidden-api-checks" value="false"/>
+
+         <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
     </test>
 </configuration>
diff --git a/apct-tests/perftests/textclassifier/OWNERS b/apct-tests/perftests/textclassifier/OWNERS
new file mode 100644
index 0000000..46b3cb8
--- /dev/null
+++ b/apct-tests/perftests/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/apct-tests/perftests/textclassifier/run.sh b/apct-tests/perftests/textclassifier/run.sh
index d36d190..9a0f4f9 100755
--- a/apct-tests/perftests/textclassifier/run.sh
+++ b/apct-tests/perftests/textclassifier/run.sh
@@ -1,8 +1,8 @@
 set -e
-build/soong/soong_ui.bash --make-mode TextClassifierPerfTests perf-setup.sh
+build/soong/soong_ui.bash --make-mode TextClassifierPerfTests perf-setup
 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/
+adb push ${OUT}/obj/EXECUTABLES/perf-setup_intermediates/perf-setup.sh /data/local/tmp/
 adb shell chmod +x /data/local/tmp/perf-setup.sh
 adb shell /data/local/tmp/perf-setup.sh
-adb shell am instrument -w -e package android.view.textclassifier com.android.perftests.textclassifier/androidx.test.runner.AndroidJUnitRunner
\ No newline at end of file
+adb shell am instrument -w -e package android.view.textclassifier com.android.perftests.textclassifier/androidx.test.runner.AndroidJUnitRunner
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
index 14a121d..324def8 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
+import android.service.textclassifier.TextClassifierService;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
@@ -25,48 +26,73 @@
 import org.junit.Before;
 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.Collections;
-import java.util.Random;
 
-@RunWith(Parameterized.class)
 @LargeTest
 public class TextClassifierPerfTest {
-    /** Request contains meaning text, rather than garbled text. */
-    private static final int ACTUAL_REQUEST = 0;
-    private static final String RANDOM_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
+    private static final String TEXT = " Oh hi Mark, the number is (323) 654-6192.\n"
+            + "Anyway, I'll meet you at 1600 Pennsylvania Avenue NW.\n"
+            + "My flight is LX 38 and I'll arrive at 8:00pm.\n"
+            + "Also, check out www.google.com.\n";
 
     @Rule
     public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
-    @Parameterized.Parameters(name = "size{0}")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][]{{ACTUAL_REQUEST}, {10}, {100}, {1000}});
-    }
-
     private TextClassifier mTextClassifier;
-    private final int mSize;
-
-    public TextClassifierPerfTest(int size) {
-        mSize = size;
-    }
 
     @Before
     public void setUp() {
         Context context = InstrumentationRegistry.getTargetContext();
-        TextClassificationManager textClassificationManager =
-                context.getSystemService(TextClassificationManager.class);
-        mTextClassifier = textClassificationManager.getTextClassifier(TextClassifier.LOCAL);
+        mTextClassifier = TextClassifierService.getDefaultTextClassifierImplementation(context);
+    }
+
+    @Test
+    public void testClassifyText() {
+        TextClassification.Request request =
+                new TextClassification.Request.Builder(TEXT, 0, TEXT.length()).build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.classifyText(request);
+        }
+    }
+
+    @Test
+    public void testSuggestSelection() {
+        // Trying to select the phone number.
+        TextSelection.Request request =
+                new TextSelection.Request.Builder(
+                        TEXT,
+                        /* startIndex= */ 28,
+                        /* endIndex= */29)
+                        .build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.suggestSelection(request);
+        }
+    }
+
+    @Test
+    public void testGenerateLinks() {
+        TextLinks.Request request =
+                new TextLinks.Request.Builder(TEXT).build();
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mTextClassifier.generateLinks(request);
+        }
     }
 
     @Test
     public void testSuggestConversationActions() {
-        String text = mSize == ACTUAL_REQUEST ? "Where are you?" : generateRandomString(mSize);
-        ConversationActions.Request request = createConversationActionsRequest(text);
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder(
+                        ConversationActions.Message.PERSON_USER_OTHERS)
+                        .setText(TEXT)
+                        .build();
+        ConversationActions.Request request = new ConversationActions.Request.Builder(
+                Collections.singletonList(message))
+                .build();
+
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mTextClassifier.suggestConversationActions(request);
@@ -75,36 +101,10 @@
 
     @Test
     public void testDetectLanguage() {
-        String text = mSize == ACTUAL_REQUEST
-                ? "これは日本語のテキストです" : generateRandomString(mSize);
-        TextLanguage.Request request = createTextLanguageRequest(text);
+        TextLanguage.Request request = new TextLanguage.Request.Builder(TEXT).build();
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             mTextClassifier.detectLanguage(request);
         }
     }
-
-    private static ConversationActions.Request createConversationActionsRequest(CharSequence text) {
-        ConversationActions.Message message =
-                new ConversationActions.Message.Builder(
-                        ConversationActions.Message.PERSON_USER_OTHERS)
-                        .setText(text)
-                        .build();
-        return new ConversationActions.Request.Builder(Collections.singletonList(message))
-                .build();
-    }
-
-    private static TextLanguage.Request createTextLanguageRequest(CharSequence text) {
-        return new TextLanguage.Request.Builder(text).build();
-    }
-
-    private static String generateRandomString(int length) {
-        Random random = new Random();
-        StringBuilder stringBuilder = new StringBuilder(length);
-        for (int i = 0; i < length; i++) {
-            int index = random.nextInt(RANDOM_CHAR_SET.length());
-            stringBuilder.append(RANDOM_CHAR_SET.charAt(index));
-        }
-        return stringBuilder.toString();
-    }
 }
diff --git a/apct-tests/perftests/utils/Android.bp b/apct-tests/perftests/utils/Android.bp
index be85816..6c46a9b 100644
--- a/apct-tests/perftests/utils/Android.bp
+++ b/apct-tests/perftests/utils/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 java_library {
     name: "apct-perftests-utils",
     static_libs: [
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index 93bf541..e192861 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -53,7 +53,8 @@
     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.
 
@@ -76,6 +77,14 @@
 
     private int mRepeatCount = 0;
 
+    /**
+     * Additional 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;
+
     // 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;
@@ -110,6 +119,15 @@
         mPaused = false;
     }
 
+    /**
+     * 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;
+    }
+
     private void beginWarmup() {
         mStartTimeNs = System.nanoTime();
         mIteration = 0;
@@ -141,6 +159,11 @@
                 Debug.stopMethodTracing();
             }
             mStats = new Stats(mResults);
+            if (mMaxCustomizedIterations > 0 && mCustomizedIterationListener != null) {
+                mState = RUNNING_CUSTOMIZED;
+                mCustomizedIterationListener.onStart(mCustomizedIterations);
+                return true;
+            }
             mState = FINISHED;
             return false;
         }
@@ -180,6 +203,15 @@
                             "Resume the benchmark before finishing each step.");
                 }
                 return true;
+            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:
@@ -240,4 +272,13 @@
         status.putLong(key + "_standardDeviation", standardDeviation());
         instrumentation.sendStatus(Activity.RESULT_OK, status);
     }
+
+    /** 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);
+    }
 }
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
index e934feb..f3bea17 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
@@ -21,6 +21,8 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
 
 /**
  * A simple activity used for testing, e.g. performance of activity switching, or as a base
@@ -28,6 +30,8 @@
  */
 public class PerfTestActivity extends Activity {
     public static final String INTENT_EXTRA_KEEP_SCREEN_ON = "keep_screen_on";
+    public static final String INTENT_EXTRA_ADD_EDIT_TEXT = "add_edit_text";
+    public static final int ID_EDITOR = 3252356;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -35,6 +39,15 @@
         if (getIntent().getBooleanExtra(INTENT_EXTRA_KEEP_SCREEN_ON, false)) {
             getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         }
+        if (getIntent().getBooleanExtra(INTENT_EXTRA_ADD_EDIT_TEXT, false)) {
+            final LinearLayout layout = new LinearLayout(this);
+            layout.setOrientation(LinearLayout.VERTICAL);
+
+            final EditText editText = new EditText(this);
+            editText.setId(ID_EDITOR);
+            layout.addView(editText);
+            setContentView(layout);
+        }
     }
 
     public static Intent createLaunchIntent(Context context) {
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
index a433d80..530dc9d 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestPackageInstaller.java
@@ -134,7 +134,7 @@
 
             Intent intent = new Intent(action);
             PendingIntent pending = PendingIntent.getBroadcast(mContext, sessionId, intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT);
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
             return pending.getIntentSender();
         }
 
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/TestUtils.java b/apct-tests/perftests/utils/src/android/perftests/utils/TestUtils.java
new file mode 100644
index 0000000..d8d3ee3
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/TestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.Instrumentation;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+public final class TestUtils {
+
+    /**
+     * Retrieves a value that needs to be obtained on the main thread.
+     *
+     * <p>A simple utility method that helps to return an object from the UI thread.</p>
+     *
+     * @param supplier callback to be called on the UI thread to return a value
+     * @param <T> Type of the value to be returned
+     * @return Value returned from {@code supplier}
+     */
+    public static <T> T getOnMainSync(@NonNull Supplier<T> supplier) {
+        final AtomicReference<T> result = new AtomicReference<>();
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> result.set(supplier.get()));
+        return result.get();
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java
new file mode 100644
index 0000000..330a19e
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 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 static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.perftests.utils.WindowPerfTestBase.executeShellCommand;
+import static android.perftests.utils.WindowPerfTestBase.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.perftests.utils.WindowPerfTestBase.SettingsSession;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.WindowManagerPolicyConstants;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.policy.PhoneWindow;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.RunListener;
+
+import java.util.List;
+
+/** Prepare the preconditions before running performance test. */
+public class WindowPerfRunPreconditionBase extends RunListener {
+    protected final String mTag = getClass().getSimpleName();
+
+    private static final String ARGUMENT_LOG_ONLY = "log";
+    private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
+    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+    private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
+    private static final String DEFAULT_PROFILING_ITERATIONS = "0";
+    private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
+    private static final long KILL_BACKGROUND_WAIT_MS = 3000;
+
+    /** The requested iterations to run with method profiling. */
+    static int sProfilingIterations;
+
+    /** The interval of sample profiling in microseconds. */
+    static int sSamplingIntervalUs;
+
+    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+    private long mWaitPreconditionDoneMs = 500;
+
+    private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>(
+            Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0),
+            value -> executeShellCommand(String.format("settings put global %s %d",
+                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)));
+
+    private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>(
+            mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_navBarInteractionMode),
+            value -> {
+                final String navOverlay;
+                switch (value) {
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
+                        break;
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+                        break;
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL:
+                    default:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
+                        break;
+                }
+                executeShellCommand("cmd overlay enable-exclusive --category " + navOverlay);
+            });
+
+    /** It only executes once before all tests. */
+    @Override
+    public void testRunStarted(Description description) {
+        final Bundle arguments = InstrumentationRegistry.getArguments();
+        // If true, it only logs the method names without running.
+        final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
+        Log.i(mTag, "arguments=" + arguments);
+        if (skip) {
+            return;
+        }
+        sProfilingIterations = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+        sSamplingIntervalUs = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
+
+        // Use same navigation mode (gesture navigation) across all devices and tests
+        // for consistency.
+        mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
+        // Keep the device awake during testing.
+        mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY);
+
+        runWithShellPermissionIdentity(() -> {
+            final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class);
+            atm.removeAllVisibleRecentTasks();
+            atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
+                    ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
+        });
+        PhoneWindow.sendCloseSystemWindows(mContext, mTag);
+
+        if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
+            runWithShellPermissionIdentity(this::killBackgroundProcesses);
+            mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
+        }
+        // Wait a while for the precondition setup to complete.
+        SystemClock.sleep(mWaitPreconditionDoneMs);
+    }
+
+    private void killBackgroundProcesses() {
+        Log.i(mTag, "Killing background processes...");
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+        if (processes == null) {
+            return;
+        }
+        for (RunningAppProcessInfo processInfo : processes) {
+            if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN
+                    && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) {
+                for (String pkg : processInfo.pkgList) {
+                    am.forceStopPackage(pkg);
+                }
+            }
+        }
+    }
+
+    /** It only executes once after all tests. */
+    @Override
+    public void testRunFinished(Result result) {
+        mNavigationModeSetting.close();
+        mStayOnWhilePluggedInSetting.close();
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java
new file mode 100644
index 0000000..ca59137
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 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 static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.SystemClock;
+
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.After;
+import org.junit.BeforeClass;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/** The base class for window related performance tests. */
+public class WindowPerfTestBase {
+    public static final long NANOS_PER_S = 1000L * 1000 * 1000;
+    public static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+
+    static boolean sIsProfilingMethod;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        final Context context = getInstrumentation().getContext();
+
+        if (!context.getSystemService(PowerManager.class).isInteractive()
+                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
+            executeShellCommand("input keyevent KEYCODE_WAKEUP");
+            executeShellCommand("wm dismiss-keyguard");
+        }
+        context.startActivity(new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+    }
+
+    @After
+    public void tearDown() {
+        // Make sure that profiling is stopped if test fails.
+        if (sIsProfilingMethod) {
+            stopProfiling();
+        }
+    }
+
+    public static UiAutomation getUiAutomation() {
+        return getInstrumentation().getUiAutomation();
+    }
+
+    public static void startAsyncAtrace(String tags) {
+        getUiAutomation().executeShellCommand("atrace -b 32768 --async_start " + tags);
+        // Avoid atrace isn't ready immediately.
+        SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
+    }
+
+    public static InputStream stopAsyncAtraceWithStream() {
+        return new ParcelFileDescriptor.AutoCloseInputStream(
+                getUiAutomation().executeShellCommand("atrace --async_stop"));
+    }
+
+    /** Starts method tracing on system server. */
+    public static void startProfiling(File basePath, String outFileName) {
+        if (!basePath.exists()) {
+            executeShellCommand("mkdir -p " + basePath);
+        }
+        final String samplingArg = WindowPerfRunPreconditionBase.sSamplingIntervalUs > 0
+                ? ("--sampling " + WindowPerfRunPreconditionBase.sSamplingIntervalUs)
+                : "";
+        executeShellCommand("am profile start " + samplingArg + " system "
+                + new File(basePath, outFileName));
+        sIsProfilingMethod = true;
+    }
+
+    /** Stops method tracing of system server. */
+    public static void stopProfiling() {
+        executeShellCommand("am profile stop system");
+        sIsProfilingMethod = false;
+    }
+
+    public static boolean sIsProfilingMethod() {
+        return sIsProfilingMethod;
+    }
+
+    /** Returns how many iterations should run with method tracing. */
+    public static int getProfilingIterations() {
+        return WindowPerfRunPreconditionBase.sProfilingIterations;
+    }
+
+    /**
+     * Executes shell command with reading the output. It may also used to block until the current
+     * command is completed.
+     */
+    public static ByteArrayOutputStream executeShellCommand(String command) {
+        final ParcelFileDescriptor pfd = getUiAutomation().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;
+    }
+
+    public static void runWithShellPermissionIdentity(Runnable runnable) {
+        getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            runnable.run();
+        } finally {
+            getUiAutomation().dropShellPermissionIdentity();
+        }
+    }
+
+    public static class SettingsSession<T> implements AutoCloseable {
+        private final Consumer<T> mSetter;
+        private final T mOriginalValue;
+        private boolean mChanged;
+
+        public SettingsSession(T originalValue, Consumer<T> setter) {
+            mOriginalValue = originalValue;
+            mSetter = setter;
+        }
+
+        public void set(T value) {
+            if (Objects.equals(value, mOriginalValue)) {
+                mChanged = false;
+                return;
+            }
+            mSetter.accept(value);
+            mChanged = true;
+        }
+
+        @Override
+        public void close() {
+            if (mChanged) {
+                mSetter.accept(mOriginalValue);
+            }
+        }
+    }
+
+    /**
+     * Provides the {@link PerfTestActivity} with an associated customizable intent.
+     */
+    public static class PerfTestActivityRuleBase extends ActivityTestRule<PerfTestActivity> {
+        protected final Intent mStartIntent =
+                new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
+
+        public PerfTestActivityRuleBase() {
+            this(false /* launchActivity */);
+        }
+
+        public PerfTestActivityRuleBase(boolean launchActivity) {
+            super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
+        }
+
+        @Override
+        public Intent getActivityIntent() {
+            return mStartIntent;
+        }
+
+        public PerfTestActivity launchActivity() {
+            return launchActivity(mStartIntent);
+        }
+    }
+}
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index f02cbcf..365824e 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
 android_test {
     name: "WmPerfTests",
     srcs: ["src/**/*.java"],
@@ -19,8 +28,11 @@
         "androidx.test.rules",
         "androidx.annotation_annotation",
         "apct-perftests-utils",
+        "collector-device-lib",
+        "platform-test-annotations",
     ],
     test_suites: ["device-tests"],
+    data: [":perfetto_artifacts"],
     platform_apis: true,
     certificate: "platform",
 }
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
index 7198176..95ede34 100644
--- a/apct-tests/perftests/windowmanager/AndroidManifest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -20,7 +20,8 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
-        <activity android:name="android.perftests.utils.PerfTestActivity">
+        <activity android:name="android.perftests.utils.PerfTestActivity"
+            android:exported="true">
           <intent-filter>
             <action android:name="com.android.perftests.core.PERFTEST" />
           </intent-filter>
@@ -28,5 +29,7 @@
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.perftests.wm"/>
+        android:targetPackage="com.android.perftests.wm">
+        <meta-data android:name="listener" android:value="android.wm.WmPerfRunListener" />
+    </instrumentation>
 </manifest>
diff --git a/apct-tests/perftests/windowmanager/AndroidTest.xml b/apct-tests/perftests/windowmanager/AndroidTest.xml
index 69d187f..6ac9f93 100644
--- a/apct-tests/perftests/windowmanager/AndroidTest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidTest.xml
@@ -21,13 +21,47 @@
         <option name="test-file-name" value="WmPerfTests.apk" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <option name="force-skip-system-props" value="true" />
+        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+        <option name="run-command" value="cmd window dismiss-keyguard" />
+        <option name="run-command" value="cmd package compile -m speed com.android.perftests.wm" />
+    </target_preparer>
+
+    <!-- Needed for pushing the trace config file -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+    </target_preparer>
+
+    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+    <option name="isolated-storage" value="false" />
+
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.perftests.wm" />
         <option name="hidden-api-checks" value="false"/>
+
+        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+
+        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+        <!-- ProcLoadListener related arguments -->
+        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+        <!-- PerfettoListener related arguments -->
+        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
     </test>
 
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/data/local/WmPerfTests" />
-        <option name="collect-on-run-ended-only" value="true" />
+        <option name="directory-keys" value="/data/local/tmp/WmPerfTests" />
+        <!-- Needed for pulling the collected trace config on to the host -->
+        <option name="pull-pattern-keys" value="perfetto_file_path" />
     </metrics_collector>
 </configuration>
diff --git a/apct-tests/perftests/windowmanager/OWNERS b/apct-tests/perftests/windowmanager/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/apct-tests/perftests/windowmanager/README.md b/apct-tests/perftests/windowmanager/README.md
new file mode 100644
index 0000000..7a0019a
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/README.md
@@ -0,0 +1,35 @@
+## Window manager performance tests
+
+### Precondition
+To reduce the variance of the test, if `perf-setup.sh` (platform_testing/scripts/perf-setup)
+is available, it is better to use the following instructions to lock CPU and GPU frequencies.
+```
+m perf-setup
+PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh
+adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH
+adb shell chmod +x $PERF_SETUP_PATH
+adb shell $PERF_SETUP_PATH
+```
+
+### Example to run
+Use `atest`
+```
+atest WmPerfTests:RelayoutPerfTest -- \
+      --module-arg WmPerfTests:instrumentation-arg:kill-bg:=true
+```
+Use `am instrument`
+```
+adb shell am instrument -w -r -e class android.wm.RelayoutPerfTest \
+          -e listener android.wm.WmPerfRunListener \
+          -e kill-bg true \
+          com.android.perftests.wm/androidx.test.runner.AndroidJUnitRunner
+```
+* `kill-bg` is optional.
+
+Test arguments
+ - kill-bg
+   * boolean: Kill background process before running test.
+ - profiling-iterations
+   * int: Run the extra iterations with enabling method profiling.
+ - profiling-sampling
+   * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
index 4ed3b4e..3a11417 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
@@ -18,7 +18,6 @@
 
 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;
@@ -37,11 +36,11 @@
 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 {
+public class InternalWindowOperationPerfTest extends WindowManagerPerfTestBase
+        implements ManualBenchmarkState.CustomizedIterationListener {
     private static final String TAG = InternalWindowOperationPerfTest.class.getSimpleName();
 
     @Rule
@@ -54,7 +53,7 @@
             "applyPostLayoutPolicy",
             "applySurfaceChanges",
             "AppTransitionReady",
-            "closeSurfaceTransactiom",
+            "closeSurfaceTransaction",
             "openSurfaceTransaction",
             "performLayout",
             "performSurfacePlacement",
@@ -68,6 +67,9 @@
             "finishActivity",
             "startActivityInner");
 
+    private boolean mIsProfiling;
+    private boolean mIsTraceStarted;
+
     @Test
     @ManualBenchmarkTest(
             targetTestDurationNs = 20 * TIME_1_S_IN_NS,
@@ -76,13 +78,13 @@
                             | StatsReport.FLAG_MAX | StatsReport.FLAG_COEFFICIENT_VAR))
     public void testLaunchAndFinishActivity() throws Throwable {
         final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
         long measuredTimeNs = 0;
-        boolean isTraceStarted = false;
 
         while (state.keepRunning(measuredTimeNs)) {
-            if (!isTraceStarted && !state.isWarmingUp()) {
-                startAsyncAtrace();
-                isTraceStarted = true;
+            if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
+                startAsyncAtrace("wm");
+                mIsTraceStarted = true;
             }
             final long startTime = SystemClock.elapsedRealtimeNanos();
             mActivityRule.launchActivity();
@@ -91,9 +93,15 @@
             measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
         }
 
-        stopAsyncAtrace();
+        if (mIsTraceStarted) {
+            stopAsyncAtrace();
+        }
 
         mTraceMarkParser.forAllSlices((key, slices) -> {
+            if (slices.size() < 2) {
+                Log.w(TAG, "No sufficient samples: " + key);
+                return;
+            }
             for (TraceMarkSlice slice : slices) {
                 state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
             }
@@ -102,20 +110,35 @@
         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);
+    private void stopAsyncAtrace() {
+        final InputStream inputStream = stopAsyncAtraceWithStream();
         try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
             String line;
             while ((line = reader.readLine()) != null) {
                 mTraceMarkParser.visit(line);
             }
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to read the result of stopped atrace", e);
+        }
+    }
+
+    @Override
+    public void onStart(int iteration) {
+        if (mIsTraceStarted) {
+            // Do not capture trace when profiling because the result will be much slower.
+            stopAsyncAtrace();
+            mIsTraceStarted = false;
+        }
+        mIsProfiling = true;
+        startProfiling(InternalWindowOperationPerfTest.class.getSimpleName()
+                + "_MethodTracing_" + iteration + ".trace");
+    }
+
+    @Override
+    public void onFinished(int iteration) {
+        stopProfiling();
+        if (iteration >= getProfilingIterations() - 1) {
+            mIsProfiling = false;
         }
     }
 }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 6122ef2..98b5938 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -24,8 +24,8 @@
 import static org.hamcrest.core.Is.is;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityTaskManager;
+import android.window.TaskSnapshot;
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -62,7 +62,8 @@
 
 @RunWith(Parameterized.class)
 @LargeTest
-public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
+public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
+        implements ManualBenchmarkState.CustomizedIterationListener {
     private static Intent sRecentsIntent;
 
     @Rule
@@ -95,7 +96,7 @@
     @BeforeClass
     public static void setUpClass() {
         // Get the permission to invoke startRecentsActivity.
-        sUiAutomation.adoptShellPermissionIdentity();
+        getUiAutomation().adoptShellPermissionIdentity();
 
         final Context context = getInstrumentation().getContext();
         final PackageManager pm = context.getPackageManager();
@@ -128,7 +129,7 @@
             ActivityManager.resumeAppSwitches();
         } catch (RemoteException ignored) {
         }
-        sUiAutomation.dropShellPermissionIdentity();
+        getUiAutomation().dropShellPermissionIdentity();
     }
 
     @Before
@@ -162,6 +163,7 @@
                     | StatsReport.FLAG_COEFFICIENT_VAR))
     public void testRecentsAnimation() throws Throwable {
         final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
         final IActivityTaskManager atm = ActivityTaskManager.getService();
 
         final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>();
@@ -224,13 +226,27 @@
             mMeasuredTimeNs = 0;
 
             final long startTime = SystemClock.elapsedRealtimeNanos();
-            atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim);
+            atm.startRecentsActivity(sRecentsIntent, 0 /* eventTime */, 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));
+            Assume.assumeTrue(recentsSemaphore.tryAcquire(
+                    sIsProfilingMethod() ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS,
+                    TimeUnit.NANOSECONDS));
         }
     }
+
+    @Override
+    public void onStart(int iteration) {
+        startProfiling(RecentsAnimationPerfTest.class.getSimpleName()
+                + "_interval_" + intervalBetweenOperations
+                + "_MethodTracing_" + iteration + ".trace");
+    }
+
+    @Override
+    public void onFinished(int iteration) {
+        stopProfiling();
+    }
 }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index f04e555..1be68f5 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -21,13 +21,12 @@
 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.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
-import android.view.DisplayCutout;
 import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.InsetsSourceControl;
@@ -37,6 +36,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.widget.LinearLayout;
+import android.window.ClientWindowFrames;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
@@ -52,7 +52,9 @@
 
 @RunWith(Parameterized.class)
 @LargeTest
-public class RelayoutPerfTest extends WindowManagerPerfTestBase {
+@Presubmit
+public class RelayoutPerfTest extends WindowManagerPerfTestBase
+        implements BenchmarkState.CustomizedIterationListener {
     private int mIteration;
 
     @Rule
@@ -91,9 +93,22 @@
         mActivityRule.runOnUiThread(() -> activity.setContentView(contentView));
         getInstrumentation().waitForIdleSync();
 
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        state.setCustomizedIterations(getProfilingIterations(), this);
         final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(),
                 () -> visibilities[mIteration++ % visibilities.length]);
-        relayoutRunner.runBenchmark(mPerfStatusReporter.getBenchmarkState());
+        relayoutRunner.runBenchmark(state);
+    }
+
+    @Override
+    public void onStart(int iteration) {
+        startProfiling(RelayoutPerfTest.class.getSimpleName() + "_" + testName
+                + "_MethodTracing_" + iteration + ".trace");
+    }
+
+    @Override
+    public void onFinished(int iteration) {
+        stopProfiling();
     }
 
     /** A dummy view to get IWindow. */
@@ -109,13 +124,7 @@
     }
 
     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 ClientWindowFrames mOutFrames = new ClientWindowFrames();
         final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration();
         final InsetsState mOutInsetsState = new InsetsState();
         final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
@@ -126,11 +135,9 @@
         final int mHeight;
         final Point mOutSurfaceSize = new Point();
         final SurfaceControl mOutSurfaceControl;
-        final SurfaceControl mOutBlastSurfaceControl = new SurfaceControl();
 
         final IntSupplier mViewVisibility;
 
-        int mSeq;
         int mFrameNumber;
         int mFlags;
 
@@ -147,12 +154,10 @@
         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, mOutControls, mOutSurfaceSize,
-                        mOutBlastSurfaceControl);
+                session.relayout(mWindow, mParams, mWidth, mHeight,
+                        mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
+                        mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
+                        mOutSurfaceSize);
             }
         }
     }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index c72cc9d..a2dc1c2 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -19,14 +19,12 @@
 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.InsetsSourceControl;
@@ -48,23 +46,21 @@
 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();
+        getUiAutomation().adoptShellPermissionIdentity();
     }
 
     @AfterClass
     public static void tearDownClass() {
-        sUiAutomation.dropShellPermissionIdentity();
+        getUiAutomation().dropShellPermissionIdentity();
     }
 
-    /** The last {@link #PROFILED_ITERATIONS} will provide the information of method profiling. */
+    /** The last customized iterations will provide the information of method profiling. */
     @Override
     public void onStart(int iteration) {
         startProfiling(WindowAddRemovePerfTest.class.getSimpleName()
@@ -80,17 +76,13 @@
     @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);
+        state.setCustomizedIterations(getProfilingIterations(), 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 mRequestedVisibility = new InsetsState();
         final InsetsState mOutInsetsState = new InsetsState();
         final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
 
@@ -109,9 +101,9 @@
                 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, mOutControls);
+                session.addToDisplay(this, mLayoutParams, View.VISIBLE,
+                        Display.DEFAULT_DISPLAY, mRequestedVisibility, inputChannel,
+                        mOutInsetsState, mOutControls);
                 final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
                 state.addExtraResult("add", elapsedTimeNsOfAdd);
 
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index 655d2f7..4b1982f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -19,125 +19,45 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import android.app.Activity;
-import android.app.KeyguardManager;
-import android.app.UiAutomation;
-import android.content.Context;
 import android.content.Intent;
-import android.os.BatteryManager;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.perftests.utils.PerfTestActivity;
-import android.provider.Settings;
+import android.perftests.utils.WindowPerfTestBase;
 
-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.AfterClass;
-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;
+public class WindowManagerPerfTestBase extends WindowPerfTestBase {
     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
+     * is in /data because while enabling method profiling of system server, it cannot write the
      * trace to external storage.
      */
-    static final File BASE_OUT_PATH = new File("/data/local/CorePerfTests");
+    static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests");
 
-    private static int sOriginalStayOnWhilePluggedIn;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        final Context context = getInstrumentation().getContext();
-        final int stayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
-        sOriginalStayOnWhilePluggedIn = -1;
-        if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
-            sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
-            // Keep the device awake during testing.
-            setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
-        }
-
-        if (!BASE_OUT_PATH.exists()) {
-            executeShellCommand("mkdir -p " + BASE_OUT_PATH);
-        }
-        if (!context.getSystemService(PowerManager.class).isInteractive()
-                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
-            executeShellCommand("input keyevent KEYCODE_WAKEUP");
-            executeShellCommand("wm dismiss-keyguard");
-        }
-        context.startActivity(new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    @AfterClass
-    public static void tearDownOnce() {
-        if (sOriginalStayOnWhilePluggedIn != -1) {
-            setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
-        }
-    }
-
-    private static void setStayOnWhilePluggedIn(int value) {
-        executeShellCommand(String.format("settings put global %s %d",
-                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value));
+    static void startProfiling(String outFileName) {
+        startProfiling(BASE_OUT_PATH, outFileName);
     }
 
     /**
-     * Executes shell command with reading the output. It may also used to block until the current
-     * command is completed.
+     * Provides an activity that is able to wait for a stable lifecycle stage.
      */
-    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(getInstrumentation().getTargetContext(), PerfTestActivity.class);
+    static class PerfTestActivityRule extends PerfTestActivityRuleBase {
         private final LifecycleListener mLifecycleListener = new LifecycleListener();
 
         PerfTestActivityRule() {
-            this(false /* launchActivity */);
         }
 
         PerfTestActivityRule(boolean launchActivity) {
-            super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
+            super(launchActivity);
         }
 
         @Override
@@ -156,21 +76,12 @@
         }
 
         @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);
         }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
new file mode 100644
index 0000000..2b0801a
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 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 android.perftests.utils.WindowPerfRunPreconditionBase;
+
+/** Prepare the preconditions before running performance test. */
+public class WmPerfRunListener extends WindowPerfRunPreconditionBase {
+}
diff --git a/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java
new file mode 100644
index 0000000..d018287
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/src/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.test.filters;
+
+import android.wm.RelayoutPerfTest;
+
+import org.junit.runner.Description;
+import org.junit.runner.manipulation.Filter;
+
+/**
+ * A static filter to have the same signature as the one in frameworks/base/tests/utils/testutils/.
+ * This doesn't share the existing library because it doesn't support parameterized test.
+ */
+public class FrameworksTestsFilter extends Filter {
+
+    private boolean mShouldRun;
+
+    @Override
+    public boolean shouldRun(Description description) {
+        final Class<?> testClass = description.getTestClass();
+        // Parameterized test methods don't have the original information. So keep the last status
+        // that matches the target class.
+        mShouldRun = (mShouldRun && testClass == null) || testClass == RelayoutPerfTest.class;
+        return mShouldRun;
+    }
+
+    @Override
+    public String describe() {
+        return "Default filter";
+    }
+}
diff --git a/apex/Android.bp b/apex/Android.bp
index 992648b..f3a9362 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -12,298 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-mainline_stubs_args =
-    "--error UnhiddenSystemApi " +
-    "--hide BroadcastBehavior " +
-    "--hide DeprecationMismatch " +
-    "--hide HiddenSuperclass " +
-    "--hide HiddenTypedefConstant " +
-    "--hide HiddenTypeParameter " +
-    "--hide MissingPermission " +
-    "--hide RequiresPermission " +
-    "--hide SdkConstant " +
-    "--hide Todo " +
-    "--hide Typo " +
-    "--hide UnavailableSymbol "
-
-// TODO: modularize this so not every module has the same whitelist
-framework_packages_to_document = [
-    "android",
-    "dalvik",
-    "java",
-    "javax",
-    "junit",
-    "org.apache.http",
-    "org.json",
-    "org.w3c.dom",
-    "org.xml.sax",
-    "org.xmlpull",
-]
-
-// TODO: remove the hiding when server classes are cleaned up.
-mainline_framework_stubs_args =
-    mainline_stubs_args +
-    "--hide-package com.android.server "
-
-priv_apps = " " +
-    "--show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
-    "\\) "
-
-module_libs = " " +
-    " --show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
-    "\\) "
-
-mainline_service_stubs_args =
-    mainline_stubs_args +
-    "--show-annotation android.annotation.SystemApi\\(" +
-        "client=android.annotation.SystemApi.Client.SYSTEM_SERVER" +
-    "\\) " +
-    "--hide-annotation android.annotation.Hide " +
-    "--hide InternalClasses " // com.android.* classes are okay in this interface
-
-// Defaults common to all mainline module java_sdk_library instances.
-java_defaults {
-    name: "framework-module-common-defaults",
-
-    // Additional annotations used for compiling both the implementation and the
-    // stubs libraries.
-    libs: ["framework-annotations-lib"],
-
-    // Framework modules are not generally shared libraries, i.e. they are not
-    // intended, and must not be allowed, to be used in a <uses-library> manifest
-    // entry.
-    shared_library: false,
-
-    // Enable api lint. This will eventually become the default for java_sdk_library
-    // but it cannot yet be turned on because some usages have not been cleaned up.
-    // TODO(b/156126315) - Remove when no longer needed.
-    api_lint: {
-        enabled: true,
-    },
-
-    // The API scope specific properties.
-    public: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
-
-    // Configure framework module specific metalava options.
-    droiddoc_options: [mainline_stubs_args],
-
-    annotations_enabled: true,
-
-    stubs_library_visibility: [
-        "//visibility:public",
-    ],
-
-    // Set the visibility of the modules creating the stubs source.
-    stubs_source_visibility: [
-        // Ignore any visibility rules specified on the java_sdk_library when
-        // setting the visibility of the stubs source modules.
-        "//visibility:override",
-
-        // Currently, the stub source is not required for anything other than building
-        // the stubs library so is private to avoid misuse.
-        "//visibility:private",
-    ],
-
-    // Collates API usages from each module for further analysis.
-    plugins: ["java_api_finder"],
-
-    // Mainline modules should only rely on 'module_lib' APIs provided by other modules
-    // and the non updatable parts of the platform.
-    sdk_version: "module_current",
-}
-
-// Defaults for mainline module provided java_sdk_library instances.
-java_defaults {
-    name: "framework-module-defaults",
-    defaults: ["framework-module-common-defaults"],
-
-    system: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
-    module_lib: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
-}
-
-// Defaults for mainline module system server provided java_sdk_library instances.
-java_defaults {
-    name: "framework-system-server-module-defaults",
-    defaults: ["framework-module-common-defaults"],
-
-    system_server: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
-}
-
-stubs_defaults {
-    name: "framework-module-stubs-defaults-publicapi",
-    args: mainline_framework_stubs_args,
-    installable: false,
-    sdk_version: "module_current",
-    annotations_enabled: true,
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    filter_packages: framework_packages_to_document,
-    check_api: {
-        current: {
-            api_file: "api/current.txt",
-            removed_api_file: "api/removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/public/api",
-    },
-}
-
-stubs_defaults {
-    name: "framework-module-stubs-defaults-systemapi",
-    args: mainline_framework_stubs_args + priv_apps,
-    libs: ["framework-annotations-lib"],
-    installable: false,
-    sdk_version: "module_current",
-    annotations_enabled: true,
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    filter_packages: framework_packages_to_document,
-    check_api: {
-        current: {
-            api_file: "api/system-current.txt",
-            removed_api_file: "api/system-removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system/api",
-    },
-}
-
-java_defaults {
-    name: "framework-module-stubs-lib-defaults-publicapi",
-    installable: false,
-    sdk_version: "module_current",
-    libs: [ "stub-annotations" ],
-    java_version: "1.8",
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/public",
-    },
-}
-
-java_defaults {
-    name: "framework-module-stubs-lib-defaults-systemapi",
-    installable: false,
-    sdk_version: "module_current",
-    libs: [ "stub-annotations" ],
-    java_version: "1.8",
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system",
-    },
-}
-
-java_defaults {
-    name: "framework-module-stubs-lib-defaults-module_libs_api",
-    installable: false,
-    sdk_version: "module_current",
-    libs: [ "stub-annotations" ],
-    java_version: "1.8",
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/module-lib",
-    },
-}
-
-// The defaults for module_libs comes in two parts - defaults for API checks
-// and defaults for stub generation. This is because we want the API txt
-// files to *only* include the module_libs_api, but the stubs to include
-// module_libs_api as well as priv_apps.
-
-stubs_defaults {
-    name: "framework-module-api-defaults-module_libs_api",
-    args: mainline_framework_stubs_args + module_libs,
-    libs: ["framework-annotations-lib"],
-    installable: false,
-    sdk_version: "module_current",
-    annotations_enabled: true,
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    filter_packages: framework_packages_to_document,
-    check_api: {
-        current: {
-            api_file: "api/module-lib-current.txt",
-            removed_api_file: "api/module-lib-removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/module-lib/api",
-    },
-}
-
-stubs_defaults {
-    name: "framework-module-stubs-defaults-module_libs_api",
-    args: mainline_framework_stubs_args + module_libs + priv_apps,
-    libs: ["framework-annotations-lib"],
-    installable: false,
-    sdk_version: "module_current",
-    annotations_enabled: true,
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    filter_packages: framework_packages_to_document,
-}
-
-stubs_defaults {
-    name: "service-module-stubs-srcs-defaults",
-    args: mainline_service_stubs_args,
-    installable: false,
-    annotations_enabled: true,
-    merge_annotations_dirs: [
-        "metalava-manual",
-    ],
-    filter_packages: ["com.android."],
-    check_api: {
-        current: {
-            api_file: "api/current.txt",
-            removed_api_file: "api/removed.txt",
-        },
-        api_lint: {
-            enabled: true,
-        },
-    },
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system-server/api",
-    },
-}
-
-// Empty for now, but a convenient place to add rules for all
-// module java_library system_server stub libs.
-java_defaults {
-    name: "service-module-stubs-defaults",
-    dist: {
-        targets: ["sdk", "win_sdk"],
-        dir: "apistubs/android/system-server",
-    },
+package {
+    default_visibility: [":__subpackages__"],
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
 }
diff --git a/apex/OWNERS b/apex/OWNERS
new file mode 100644
index 0000000..b3e81b9
--- /dev/null
+++ b/apex/OWNERS
@@ -0,0 +1 @@
+file:platform/packages/modules/common:/OWNERS
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
new file mode 100644
index 0000000..977e610
--- /dev/null
+++ b/apex/appsearch/Android.bp
@@ -0,0 +1,75 @@
+// 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+apex {
+    name: "com.android.appsearch",
+    manifest: "apex_manifest.json",
+    bootclasspath_fragments: ["com.android.appsearch-bootclasspath-fragment"],
+    systemserverclasspath_fragments: ["com.android.appsearch-systemserverclasspath-fragment"],
+    key: "com.android.appsearch.key",
+    certificate: ":com.android.appsearch.certificate",
+    updatable: false,
+    jni_libs: ["libicing"],
+    generate_hashtree: false,
+}
+
+apex_key {
+    name: "com.android.appsearch.key",
+    public_key: "com.android.appsearch.avbpubkey",
+    private_key: "com.android.appsearch.pem",
+}
+
+android_app_certificate {
+    name: "com.android.appsearch.certificate",
+    // This will use com.android.appsearch.x509.pem (the cert) and
+    // com.android.appsearch.pk8 (the private key)
+    certificate: "com.android.appsearch",
+}
+
+// Encapsulate the contributions made by the com.android.appsearch to the bootclasspath.
+bootclasspath_fragment {
+    name: "com.android.appsearch-bootclasspath-fragment",
+    contents: ["framework-appsearch"],
+    apex_available: ["com.android.appsearch"],
+
+    // The bootclasspath_fragments that provide APIs on which this depends.
+    fragments: [
+        {
+            apex: "com.android.art",
+            module: "art-bootclasspath-fragment",
+        },
+    ],
+
+    // Additional stubs libraries that this fragment's contents use which are
+    // not provided by another bootclasspath_fragment.
+    additional_stubs: [
+        "android-non-updatable",
+    ],
+}
+
+// Encapsulate the contributions made by the com.android.appsearch to the systemserverclasspath.
+systemserverclasspath_fragment {
+    name: "com.android.appsearch-systemserverclasspath-fragment",
+    contents: ["service-appsearch"],
+    apex_available: ["com.android.appsearch"],
+}
diff --git a/apex/appsearch/OWNERS b/apex/appsearch/OWNERS
new file mode 100644
index 0000000..1703369
--- /dev/null
+++ b/apex/appsearch/OWNERS
@@ -0,0 +1,3 @@
+adorokhine@google.com
+sudheersai@google.com
+yamasani@google.com
diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json
new file mode 100644
index 0000000..39a2d38
--- /dev/null
+++ b/apex/appsearch/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.appsearch",
+  "version": 300000000
+}
diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey
new file mode 100644
index 0000000..4e5acae
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.avbpubkey
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem
new file mode 100644
index 0000000..4ed5945
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAro9f/jvoIsj6ywuRmuUQS8UtprhohJitrovDMfm/T2R/WQvy
+AvUxgetyF4XvBPCDRqCsGxXCJMQOn1furrAeTmWbGHPhA0PI1Ys/qtfNMbh9THyn
+70I2c4X70CUQ+8/Y8BJ8CAB4iER/s9QtD28QLvM2BBUzRoKUSBGUYNMlYobjgRdK
+57V7yg48LkvUIg1fzIW3M5gCgOXa0u1xOadKX3m7tzCboHcXp5anfWX5PH1+okRu
+jzdI8OjtUq23qhoRw5Skz0Vbf4a+8t3kT3slF/Q7O8LoRPwpZsvIcvTyCGAqlra7
+2L2LN4H1p+u2ko3r/QmRbJn2eXW07elkyrggXMyn2rTxibQgk53wYfSavMyNd/E7
++de/uJ60l2aPa+5KUaR8eYwchXEELdqQ+zRgSZ2711xCaY4glEj7DT6VlEEdr26x
+akX0ra7e2sVGv1um/dvSyVO5aFKKjVvo4LqhWKWO8yvDMxmDDTNatvWhY2Bhd3RA
+0hilYpWQFb9Tv5f4E0tZmfvlddgux7sw++Y/RIimBFoSyf5AezAUIFYYoYvEzytB
+muq1/ecNHr+Z2tZMxN88sJVhzRzD9tKUyXhvxOV2Lg9TIeVTWGwQqgSnHWtIe+1p
+cw8inPfYEhP4Q+3W/RlPvNdu75x8Nj2aG7bxZnhoQDRDw5ddgma27I+a8esCAwEA
+AQKCAgBsNh9I6HRAVBz8kCBkSEnw3rwtFTZdtJQ+lw+bRHpvShqT5g7R/JQDOSTS
+JkoE4uBOgT4P0E45Inz6FLW2/yDacqxR3UwJDRVMI/WFACCJCRhLuR8V+BLvTIjN
+AJ1lrPSL5rmS8E/IEcakgQyp+6ypnkXHBCl0NXCcuKEl4N7VFE+mb/0UZPHnUSnH
+fWR085uGmwH17u7mXxdnGKDPH8DALSPMLUrcj9dPIdqUpwl5kUZWa1uqVphWF98/
+GMe5oE2Q0+3TO+i7xplKz3lAOFPHZLTvmCUK1tMHkZ6ifOwpewwLwB30/5N1BpB1
+126nrWk0xKCtFUixBOHzdnLwJHKSbi7chQU5q39oAJoTfxdmAJlaG0zQHUQZ44MQ
+gemzSA7uJbtoAOAZVF1K14xbIpnfidqTB7N3RCmiJE+/Hpkq6PxgPfu5rqocPbPC
+t0FgJ4NXNmKOAuJllSlrrHATcUOhF4g5pX7tvOc8X4y7bvfwOmtw5ez3INKMF0q6
+/y0vVCi6N1Z7CTa9eY8feZ1PImk/Fkq4NInSPyx7ZE3pLYmsvuJjliFrWo9TRVae
+Dt5vvBKBOpAfhDiHkeXbX7Raj2B6c6adF4no/3SAVlAjIq1iBVjfQWyHAGUoEW1O
+u3LdHTIb6gSTLJ4AfryEKrOE+1VMlYt92GwX692KKXMaJjytSQKCAQEA3pYbl8HD
+Y++UyEN5VzWAQedT3//GDwpDfgdERe2E4smYrkVNJ2WAG2SqY1A35DIl8be3eHvl
+soaL38j48ailfDYY9tI+IlapNh+VOLej+HiOytaPlLhcv2FpSC2qZT4EiU6IBXLo
++l6FrmD/VQXTjvoktzsDB/n1t4Dfa3Ogf+lLf1Jxr94YpEnDh18V5ofj78SplVLm
+NrzsHxAafE4Ni2a7dyWjcDYIuL7FTShT+0K4W45tRr+CGxThxu7LEe7zw4Z1IagU
+jJNtXjvDD/Zw4UTqI6RwWGZsu6UjPS6LHhOqnWqflWmFRIfMbDkuWvnGZTM9DkVg
+kk1+BNi1PECZXwKCAQEAyMOjbVo6XV3lFN0X8TpHyg/z9ar00/SE7WEJHqPSuzYT
+rSfU4vDDlaPAwkYvGi9ZKi9VM+R3CyBNxnK9Yq6NurHhhrYcAwdS/hGLT1K2o0Y8
+Pgv7gZCFb+SIwLBhlUG9otGULcBzLneqgVUqyMG6IoCjuC2LRyB71Xc2UMyg6n/f
+XpV2RTMb8f+26cgm6nj0SDAfgpr8HV6uNV80c6l1A8gq86nUWwiVAEUdmExSDe7J
+shsfWAj8RSErqDXf1BtEdPLJUSIPX5VXkzAXOXIkengwVno0vv0dBN8uraS8iQSG
+0JsJLLcw9b5kvnh6FEbE7POsIqKyCZV9VADwO6YW9QKCAQBYQsdwNqoGv6KMgozj
+8tgHyfWtVduwbQ50M+dznwpZbzz2pY5Bd/MDabhSpyVyfBwlrAa5ZM+hKc7fDu7/
+zDLKfR0LCjUPIrP4PS/LjK4dQZjFf6zxeOV2EedQcqMlgCEGXTh8iKMvXDm/+sBk
+c2n/QNs8OM8r44b2m8h78B6NefGw6/0ekn/M7V72F9M0VWAh3Cauim+09tbePmFy
+NvUR+MuPJEKZpSNyNltADCS49izqSSC1tAygNniMjHXDh6/rMS7TCLYVRARTIHlp
+o/wAp3X8aiEOPJcTFRlTElihtYSq5POgqHXqxbpek5H5CyALUvT76rCvcsDspQ3A
+dZEbAoIBAQCoLEmP5o8Rev/UdEgECB/uwWJIngYsLp3TAv/SrMRvkiL1X3JTD/+m
+L9/eXVBDjPoR/khPCcg2h77ex2qhaTrL8wnKAG6CkvYQYb3impTnPIRmLT9nDxrX
+2gY78wQrNUCXTRvlH1rcx90KLb+DH9S95ig+tdf/otRYwl27XU5GYQtJfcXuvZth
+IiWku8btjpiCh909WHpsV81yY+faI08j9d8U8WQzRYMbEMpzsyrhBO/rxBCDfDNl
+7R1W8JooYRb9KAs/bVqXZNBROW2a72RjOp6zMfdRLVHLrPC7AE32MNaFk/khfesD
+T5OwgdcxeP6oxo2hDcw5fwHXBlo2fTCpAoIBAQChgjv5AfQ50spqvHy6MNem4tV0
+L0IsxmNLsi8X2a6s4kStwUzOxDA8c/e54XabxQNZ0ERU1q+bgbG7PWC4twDMPR8i
+2DO6rgqSK4MjGOTgAoeDuy3mElFQmCLRs04Wf4jh8kPi217WFlYBynh2HmBKbh42
+JmIrLetbKEK13FXRvMkgZcX4OIDrT5TOvev4VZArU8PTRlWv3sqsKAVXjX0clGHf
+I0/2kSsr2qq1UY7JrYWZsZ9uqz2ZH0pF19a6O/Cq4uqTYoL+sYzFTSeFmChRjV1g
+ancTvTn9lcBqECDMgq5DE/p96Oxg/t8elalR6WDUlysafphVz3nTuyMTh7ka
+-----END RSA PRIVATE KEY-----
diff --git a/apex/appsearch/com.android.appsearch.pk8 b/apex/appsearch/com.android.appsearch.pk8
new file mode 100644
index 0000000..77e98b2
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pk8
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem
new file mode 100644
index 0000000..e37c4b9
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGETCCA/mgAwIBAgIUGl+MIvpEi0+TWzj0ieh6WtjXmP8wDQYJKoZIhvcNAQEL
+BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRIwEAYDVQQDDAlhcHBzZWFyY2gxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRA
+YW5kcm9pZC5jb20wIBcNMTkxMTIwMjMxNTM1WhgPNDc1NzEwMTYyMzE1MzVaMIGW
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDES
+MBAGA1UEAwwJYXBwc2VhcmNoMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv
+aWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsyPlp3q3P9Xg
+W1WhIwQiF9em9oqaGQ/3dbIxickAy591qcRbpHb4lDTZusRECfqlV215mV+lv5x4
+EhOnId3uPKBAJ/YDtL7zUW6TWL7to7zEnUqSIKTcoQzNF2EiCeGuRhrtgYvAD3HQ
+dwr4xrbSADbDArF04A49voLpsmq1fyNgl86VISiMRqoSLJnA6eghlduuOt+nf252
+6WgxDs/JrO/eK70q0+RwmWzVJ/tVr+36a65N4EHhfL4t2hdV0k0XFob7hBn7XWzC
+QrSR3jCvE3yAfAr3tq5c19/WWBA7V45nEHzXyAvBUHWubYvDi+vm/yzqU2rQwScC
+bzp4zK4CnhBHqb4gHoy0+kfFIwJ1A3GT2pl3ba/NsIYgliMtPQfkDV5PE5RTNcwH
+21ewH7vm2+spQv5Z/2TEV2lEHlp2vuAliyn2AT4u1ginr6vtBRFLmpPeziFcfB0y
+7h04GctZpX8odz+XI7aMDe47RNu9XyJX0vulntxmlDF76k8Z9DIXg02hY+yc/i7+
+2ztnj1eXL51p+HyhK5VbvJWbKkVaMQijlbuIMYNzMA6L0WHWRc2Cux9UDODMGoiC
+w09JpqudCS/95I/F1xaWJ/Kh3vKeQshHAz0hrL7v7wpjmfeXf6NGsWJGy+giCwZj
+ABtn9nFQoesgi7M1LeazD5Q/4v4AMaUCAwEAAaNTMFEwHQYDVR0OBBYEFJpHCy2Y
+3qaL6cLpE9fe53L61KEEMB8GA1UdIwQYMBaAFJpHCy2Y3qaL6cLpE9fe53L61KEE
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGDYAcOhbOYcDB2K
+WDZka+FCORFFvz4nLQGE7Z9TAn1g7XusM2KbXlb2drIN6CWOFlnKQrUsNsAHrc+s
+tl+A1vC3/NfYKKBVuizPx/kHUgz3k/UIJzbzEu/uCJd86idcJoUTqC/qEJAeeQqM
+XpsNP1Yg7oyzZT8sFlUAKeDeXJ7fIDXR6nduUQ6uJXkee/5JF3VedHdgHAUsC19/
+KHhyVU3MLDUNBdAmM79+DsdVYi2Pw31jojMu95Zz1MYTRBcgQAiEw5nncr38k6ac
+Gy+JffgJR68FzI4QLBSxnDRFD2zXJ09lpP6Sjb1FVcDzk7Bi/EQDLBkrkbeLsk5F
+a0xz9VoJ3kM7Cc4R9MXN4ZWuePjdJwgasnHmllsXn45R9odgJgmfzuUwtgNw/XKQ
+QcQl7Q9QUrBCqIoHijxscUZCBSmIHVNBBDckRAmSXHeWMRlO3uBR4IA/Jfrt//4f
+uc7CNUp+LQ6EzBXJOVFrXRtau6Oj+jM1+fzxKo1uV2+T+GdVEE5jeF/6nB3qna6h
+2NmyLqbqeqp2QxgzBWSGy8Ugs6zg4wItJBqOoRLKKFxTJu5OAzJ4fUA+g7WFXNhR
+kG56SJ863LZoORKHWE72oXYeIW98Tq0qKLH3NzH5L4tfX8DeBTq+APezHetH1ljA
+D0avPy62g0i643bbpwZgezBgRIKL
+-----END CERTIFICATE-----
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
new file mode 100644
index 0000000..8964668
--- /dev/null
+++ b/apex/appsearch/framework/Android.bp
@@ -0,0 +1,68 @@
+// 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "framework-appsearch-sources",
+    srcs: [
+        ":framework-appsearch-internal-sources",
+        ":framework-appsearch-external-sources",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+filegroup {
+    name: "framework-appsearch-internal-sources",
+    srcs: [
+        "java/**/*.java",
+        "java/**/*.aidl",
+    ],
+    exclude_srcs: [":framework-appsearch-external-sources"],
+    path: "java",
+}
+
+filegroup {
+    name: "framework-appsearch-external-sources",
+    srcs: [
+        "java/external/**/*.java",
+        "java/external/**/*.aidl",
+    ],
+    path: "java/external",
+}
+
+java_sdk_library {
+    name: "framework-appsearch",
+    srcs: [":framework-appsearch-sources"],
+    sdk_version: "module_current",
+    static_libs: [
+        // This list must be kept in sync with jarjar.txt
+        "modules-utils-preconditions",
+    ],
+    defaults: ["framework-module-defaults"],
+    permitted_packages: ["android.app.appsearch"],
+    jarjar_rules: "jarjar-rules.txt",
+    apex_available: ["com.android.appsearch"],
+    impl_library_visibility: [
+        "//frameworks/base/apex/appsearch/service",
+    ],
+    unsafe_ignore_missing_latest_api: true, // TODO(b/146218515) should be removed
+}
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
new file mode 100644
index 0000000..761405c
--- /dev/null
+++ b/apex/appsearch/framework/api/current.txt
@@ -0,0 +1,460 @@
+// Signature format: 2.0
+package android.app.appsearch {
+
+  public final class AppSearchBatchResult<KeyType, ValueType> {
+    method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getAll();
+    method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getFailures();
+    method @NonNull public java.util.Map<KeyType,ValueType> getSuccesses();
+    method public boolean isSuccess();
+  }
+
+  public static final class AppSearchBatchResult.Builder<KeyType, ValueType> {
+    ctor public AppSearchBatchResult.Builder();
+    method @NonNull public android.app.appsearch.AppSearchBatchResult<KeyType,ValueType> build();
+    method @NonNull public android.app.appsearch.AppSearchBatchResult.Builder<KeyType,ValueType> setFailure(@NonNull KeyType, int, @Nullable String);
+    method @NonNull public android.app.appsearch.AppSearchBatchResult.Builder<KeyType,ValueType> setResult(@NonNull KeyType, @NonNull android.app.appsearch.AppSearchResult<ValueType>);
+    method @NonNull public android.app.appsearch.AppSearchBatchResult.Builder<KeyType,ValueType> setSuccess(@NonNull KeyType, @Nullable ValueType);
+  }
+
+  public class AppSearchManager {
+    method public void createGlobalSearchSession(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.GlobalSearchSession>>);
+    method public void createSearchSession(@NonNull android.app.appsearch.AppSearchManager.SearchContext, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.AppSearchSession>>);
+  }
+
+  public static final class AppSearchManager.SearchContext {
+    method @NonNull public String getDatabaseName();
+  }
+
+  public static final class AppSearchManager.SearchContext.Builder {
+    ctor public AppSearchManager.SearchContext.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchManager.SearchContext build();
+  }
+
+  public final class AppSearchResult<ValueType> {
+    method @Nullable public String getErrorMessage();
+    method public int getResultCode();
+    method @Nullable public ValueType getResultValue();
+    method public boolean isSuccess();
+    method @NonNull public static <ValueType> android.app.appsearch.AppSearchResult<ValueType> newFailedResult(int, @Nullable String);
+    method @NonNull public static <ValueType> android.app.appsearch.AppSearchResult<ValueType> newSuccessfulResult(@Nullable ValueType);
+    field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
+    field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
+    field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
+    field public static final int RESULT_IO_ERROR = 4; // 0x4
+    field public static final int RESULT_NOT_FOUND = 6; // 0x6
+    field public static final int RESULT_OK = 0; // 0x0
+    field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+    field public static final int RESULT_SECURITY_ERROR = 8; // 0x8
+    field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
+  }
+
+  public final class AppSearchSchema {
+    method @NonNull public java.util.List<android.app.appsearch.AppSearchSchema.PropertyConfig> getProperties();
+    method @NonNull public String getSchemaType();
+  }
+
+  public static final class AppSearchSchema.BooleanPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+  }
+
+  public static final class AppSearchSchema.BooleanPropertyConfig.Builder {
+    ctor public AppSearchSchema.BooleanPropertyConfig.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.BooleanPropertyConfig.Builder setCardinality(int);
+  }
+
+  public static final class AppSearchSchema.Builder {
+    ctor public AppSearchSchema.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.Builder addProperty(@NonNull android.app.appsearch.AppSearchSchema.PropertyConfig);
+    method @NonNull public android.app.appsearch.AppSearchSchema build();
+  }
+
+  public static final class AppSearchSchema.BytesPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+  }
+
+  public static final class AppSearchSchema.BytesPropertyConfig.Builder {
+    ctor public AppSearchSchema.BytesPropertyConfig.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.BytesPropertyConfig.Builder setCardinality(int);
+  }
+
+  public static final class AppSearchSchema.DocumentPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+    method @NonNull public String getSchemaType();
+    method public boolean shouldIndexNestedProperties();
+  }
+
+  public static final class AppSearchSchema.DocumentPropertyConfig.Builder {
+    ctor public AppSearchSchema.DocumentPropertyConfig.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setCardinality(int);
+    method @NonNull public android.app.appsearch.AppSearchSchema.DocumentPropertyConfig.Builder setShouldIndexNestedProperties(boolean);
+  }
+
+  public static final class AppSearchSchema.DoublePropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+  }
+
+  public static final class AppSearchSchema.DoublePropertyConfig.Builder {
+    ctor public AppSearchSchema.DoublePropertyConfig.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.DoublePropertyConfig.Builder setCardinality(int);
+  }
+
+  public static final class AppSearchSchema.LongPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+  }
+
+  public static final class AppSearchSchema.LongPropertyConfig.Builder {
+    ctor public AppSearchSchema.LongPropertyConfig.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.LongPropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.LongPropertyConfig.Builder setCardinality(int);
+  }
+
+  public abstract static class AppSearchSchema.PropertyConfig {
+    method public int getCardinality();
+    method @NonNull public String getName();
+    field public static final int CARDINALITY_OPTIONAL = 2; // 0x2
+    field public static final int CARDINALITY_REPEATED = 1; // 0x1
+    field public static final int CARDINALITY_REQUIRED = 3; // 0x3
+  }
+
+  public static final class AppSearchSchema.StringPropertyConfig extends android.app.appsearch.AppSearchSchema.PropertyConfig {
+    method public int getIndexingType();
+    method public int getTokenizerType();
+    field public static final int INDEXING_TYPE_EXACT_TERMS = 1; // 0x1
+    field public static final int INDEXING_TYPE_NONE = 0; // 0x0
+    field public static final int INDEXING_TYPE_PREFIXES = 2; // 0x2
+    field public static final int TOKENIZER_TYPE_NONE = 0; // 0x0
+    field public static final int TOKENIZER_TYPE_PLAIN = 1; // 0x1
+  }
+
+  public static final class AppSearchSchema.StringPropertyConfig.Builder {
+    ctor public AppSearchSchema.StringPropertyConfig.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig build();
+    method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setCardinality(int);
+    method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setIndexingType(int);
+    method @NonNull public android.app.appsearch.AppSearchSchema.StringPropertyConfig.Builder setTokenizerType(int);
+  }
+
+  public final class AppSearchSession implements java.io.Closeable {
+    method public void close();
+    method public void getByDocumentId(@NonNull android.app.appsearch.GetByDocumentIdRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,android.app.appsearch.GenericDocument>);
+    method public void getNamespaces(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.Set<java.lang.String>>>);
+    method public void getSchema(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.GetSchemaResponse>>);
+    method public void getStorageInfo(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.StorageInfo>>);
+    method public void put(@NonNull android.app.appsearch.PutDocumentsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
+    method public void remove(@NonNull android.app.appsearch.RemoveByDocumentIdRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.appsearch.BatchResultCallback<java.lang.String,java.lang.Void>);
+    method public void remove(@NonNull String, @NonNull android.app.appsearch.SearchSpec, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+    method public void reportUsage(@NonNull android.app.appsearch.ReportUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
+    method public void setSchema(@NonNull android.app.appsearch.SetSchemaRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<android.app.appsearch.SetSchemaResponse>>);
+  }
+
+  public interface BatchResultCallback<KeyType, ValueType> {
+    method public void onResult(@NonNull android.app.appsearch.AppSearchBatchResult<KeyType,ValueType>);
+    method public default void onSystemError(@Nullable Throwable);
+  }
+
+  public class GenericDocument {
+    ctor protected GenericDocument(@NonNull android.app.appsearch.GenericDocument);
+    method public long getCreationTimestampMillis();
+    method @NonNull public String getId();
+    method public static int getMaxIndexedProperties();
+    method @NonNull public String getNamespace();
+    method @Nullable public Object getProperty(@NonNull String);
+    method public boolean getPropertyBoolean(@NonNull String);
+    method @Nullable public boolean[] getPropertyBooleanArray(@NonNull String);
+    method @Nullable public byte[] getPropertyBytes(@NonNull String);
+    method @Nullable public byte[][] getPropertyBytesArray(@NonNull String);
+    method @Nullable public android.app.appsearch.GenericDocument getPropertyDocument(@NonNull String);
+    method @Nullable public android.app.appsearch.GenericDocument[] getPropertyDocumentArray(@NonNull String);
+    method public double getPropertyDouble(@NonNull String);
+    method @Nullable public double[] getPropertyDoubleArray(@NonNull String);
+    method public long getPropertyLong(@NonNull String);
+    method @Nullable public long[] getPropertyLongArray(@NonNull String);
+    method @NonNull public java.util.Set<java.lang.String> getPropertyNames();
+    method @Nullable public String getPropertyString(@NonNull String);
+    method @Nullable public String[] getPropertyStringArray(@NonNull String);
+    method @NonNull public String getSchemaType();
+    method public int getScore();
+    method public long getTtlMillis();
+  }
+
+  public static class GenericDocument.Builder<BuilderType extends android.app.appsearch.GenericDocument.Builder> {
+    ctor public GenericDocument.Builder(@NonNull String, @NonNull String, @NonNull String);
+    method @NonNull public android.app.appsearch.GenericDocument build();
+    method @NonNull public BuilderType setCreationTimestampMillis(long);
+    method @NonNull public BuilderType setPropertyBoolean(@NonNull String, @NonNull boolean...);
+    method @NonNull public BuilderType setPropertyBytes(@NonNull String, @NonNull byte[]...);
+    method @NonNull public BuilderType setPropertyDocument(@NonNull String, @NonNull android.app.appsearch.GenericDocument...);
+    method @NonNull public BuilderType setPropertyDouble(@NonNull String, @NonNull double...);
+    method @NonNull public BuilderType setPropertyLong(@NonNull String, @NonNull long...);
+    method @NonNull public BuilderType setPropertyString(@NonNull String, @NonNull java.lang.String...);
+    method @NonNull public BuilderType setScore(@IntRange(from=0, to=java.lang.Integer.MAX_VALUE) int);
+    method @NonNull public BuilderType setTtlMillis(long);
+  }
+
+  public final class GetByDocumentIdRequest {
+    method @NonNull public java.util.Set<java.lang.String> getIds();
+    method @NonNull public String getNamespace();
+    method @NonNull public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getProjections();
+    field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
+  }
+
+  public static final class GetByDocumentIdRequest.Builder {
+    ctor public GetByDocumentIdRequest.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.GetByDocumentIdRequest.Builder addIds(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.GetByDocumentIdRequest.Builder addIds(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.GetByDocumentIdRequest.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.GetByDocumentIdRequest build();
+  }
+
+  public final class GetSchemaResponse {
+    method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+    method @IntRange(from=0) public int getVersion();
+  }
+
+  public static final class GetSchemaResponse.Builder {
+    ctor public GetSchemaResponse.Builder();
+    method @NonNull public android.app.appsearch.GetSchemaResponse.Builder addSchema(@NonNull android.app.appsearch.AppSearchSchema);
+    method @NonNull public android.app.appsearch.GetSchemaResponse build();
+    method @NonNull public android.app.appsearch.GetSchemaResponse.Builder setVersion(@IntRange(from=0) int);
+  }
+
+  public class GlobalSearchSession implements java.io.Closeable {
+    method public void close();
+    method public void reportSystemUsage(@NonNull android.app.appsearch.ReportSystemUsageRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.lang.Void>>);
+    method @NonNull public android.app.appsearch.SearchResults search(@NonNull String, @NonNull android.app.appsearch.SearchSpec);
+  }
+
+  public abstract class Migrator {
+    ctor public Migrator();
+    method @NonNull @WorkerThread public abstract android.app.appsearch.GenericDocument onDowngrade(int, int, @NonNull android.app.appsearch.GenericDocument);
+    method @NonNull @WorkerThread public abstract android.app.appsearch.GenericDocument onUpgrade(int, int, @NonNull android.app.appsearch.GenericDocument);
+    method public abstract boolean shouldMigrate(int, int);
+  }
+
+  public class PackageIdentifier {
+    ctor public PackageIdentifier(@NonNull String, @NonNull byte[]);
+    method @NonNull public String getPackageName();
+    method @NonNull public byte[] getSha256Certificate();
+  }
+
+  public final class PutDocumentsRequest {
+    method @NonNull public java.util.List<android.app.appsearch.GenericDocument> getGenericDocuments();
+  }
+
+  public static final class PutDocumentsRequest.Builder {
+    ctor public PutDocumentsRequest.Builder();
+    method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocuments(@NonNull android.app.appsearch.GenericDocument...);
+    method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocuments(@NonNull java.util.Collection<? extends android.app.appsearch.GenericDocument>);
+    method @NonNull public android.app.appsearch.PutDocumentsRequest build();
+  }
+
+  public final class RemoveByDocumentIdRequest {
+    method @NonNull public java.util.Set<java.lang.String> getIds();
+    method @NonNull public String getNamespace();
+  }
+
+  public static final class RemoveByDocumentIdRequest.Builder {
+    ctor public RemoveByDocumentIdRequest.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.RemoveByDocumentIdRequest.Builder addIds(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.RemoveByDocumentIdRequest.Builder addIds(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.RemoveByDocumentIdRequest build();
+  }
+
+  public final class ReportSystemUsageRequest {
+    method @NonNull public String getDatabaseName();
+    method @NonNull public String getDocumentId();
+    method @NonNull public String getNamespace();
+    method @NonNull public String getPackageName();
+    method public long getUsageTimestampMillis();
+  }
+
+  public static final class ReportSystemUsageRequest.Builder {
+    ctor public ReportSystemUsageRequest.Builder(@NonNull String, @NonNull String, @NonNull String, @NonNull String);
+    method @NonNull public android.app.appsearch.ReportSystemUsageRequest build();
+    method @NonNull public android.app.appsearch.ReportSystemUsageRequest.Builder setUsageTimestampMillis(long);
+  }
+
+  public final class ReportUsageRequest {
+    method @NonNull public String getDocumentId();
+    method @NonNull public String getNamespace();
+    method public long getUsageTimestampMillis();
+  }
+
+  public static final class ReportUsageRequest.Builder {
+    ctor public ReportUsageRequest.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.app.appsearch.ReportUsageRequest build();
+    method @NonNull public android.app.appsearch.ReportUsageRequest.Builder setUsageTimestampMillis(long);
+  }
+
+  public final class SearchResult {
+    method @NonNull public String getDatabaseName();
+    method @NonNull public android.app.appsearch.GenericDocument getGenericDocument();
+    method @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatchInfos();
+    method @NonNull public String getPackageName();
+    method public double getRankingSignal();
+  }
+
+  public static final class SearchResult.Builder {
+    ctor public SearchResult.Builder(@NonNull String, @NonNull String);
+    method @NonNull public android.app.appsearch.SearchResult.Builder addMatchInfo(@NonNull android.app.appsearch.SearchResult.MatchInfo);
+    method @NonNull public android.app.appsearch.SearchResult build();
+    method @NonNull public android.app.appsearch.SearchResult.Builder setGenericDocument(@NonNull android.app.appsearch.GenericDocument);
+    method @NonNull public android.app.appsearch.SearchResult.Builder setRankingSignal(double);
+  }
+
+  public static final class SearchResult.MatchInfo {
+    method @NonNull public CharSequence getExactMatch();
+    method @NonNull public android.app.appsearch.SearchResult.MatchRange getExactMatchRange();
+    method @NonNull public String getFullText();
+    method @NonNull public String getPropertyPath();
+    method @NonNull public CharSequence getSnippet();
+    method @NonNull public android.app.appsearch.SearchResult.MatchRange getSnippetRange();
+  }
+
+  public static final class SearchResult.MatchInfo.Builder {
+    ctor public SearchResult.MatchInfo.Builder(@NonNull String);
+    method @NonNull public android.app.appsearch.SearchResult.MatchInfo build();
+    method @NonNull public android.app.appsearch.SearchResult.MatchInfo.Builder setExactMatchRange(@NonNull android.app.appsearch.SearchResult.MatchRange);
+    method @NonNull public android.app.appsearch.SearchResult.MatchInfo.Builder setSnippetRange(@NonNull android.app.appsearch.SearchResult.MatchRange);
+  }
+
+  public static final class SearchResult.MatchRange {
+    ctor public SearchResult.MatchRange(int, int);
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public class SearchResults implements java.io.Closeable {
+    method public void close();
+    method public void getNextPage(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.appsearch.AppSearchResult<java.util.List<android.app.appsearch.SearchResult>>>);
+  }
+
+  public final class SearchSpec {
+    method @NonNull public java.util.List<java.lang.String> getFilterNamespaces();
+    method @NonNull public java.util.List<java.lang.String> getFilterPackageNames();
+    method @NonNull public java.util.List<java.lang.String> getFilterSchemas();
+    method public int getMaxSnippetSize();
+    method public int getOrder();
+    method @NonNull public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getProjections();
+    method public int getRankingStrategy();
+    method public int getResultCountPerPage();
+    method public int getResultGroupingLimit();
+    method public int getResultGroupingTypeFlags();
+    method public int getSnippetCount();
+    method public int getSnippetCountPerProperty();
+    method public int getTermMatch();
+    field public static final int GROUPING_TYPE_PER_NAMESPACE = 2; // 0x2
+    field public static final int GROUPING_TYPE_PER_PACKAGE = 1; // 0x1
+    field public static final int ORDER_ASCENDING = 1; // 0x1
+    field public static final int ORDER_DESCENDING = 0; // 0x0
+    field public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
+    field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+    field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+    field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+    field public static final int RANKING_STRATEGY_RELEVANCE_SCORE = 3; // 0x3
+    field public static final int RANKING_STRATEGY_SYSTEM_USAGE_COUNT = 6; // 0x6
+    field public static final int RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP = 7; // 0x7
+    field public static final int RANKING_STRATEGY_USAGE_COUNT = 4; // 0x4
+    field public static final int RANKING_STRATEGY_USAGE_LAST_USED_TIMESTAMP = 5; // 0x5
+    field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+    field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+  }
+
+  public static final class SearchSpec.Builder {
+    ctor public SearchSpec.Builder();
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterNamespaces(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterNamespaces(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterPackageNames(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterPackageNames(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterSchemas(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addFilterSchemas(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder addProjection(@NonNull String, @NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SearchSpec build();
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setMaxSnippetSize(@IntRange(from=0, to=0x2710) int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setOrder(int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setRankingStrategy(int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setResultCountPerPage(@IntRange(from=0, to=0x2710) int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setResultGrouping(int, int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setSnippetCount(@IntRange(from=0, to=0x2710) int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setSnippetCountPerProperty(@IntRange(from=0, to=0x2710) int);
+    method @NonNull public android.app.appsearch.SearchSpec.Builder setTermMatch(int);
+  }
+
+  public final class SetSchemaRequest {
+    method @NonNull public java.util.Map<java.lang.String,android.app.appsearch.Migrator> getMigrators();
+    method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+    method @NonNull public java.util.Set<java.lang.String> getSchemasNotDisplayedBySystem();
+    method @NonNull public java.util.Map<java.lang.String,java.util.Set<android.app.appsearch.PackageIdentifier>> getSchemasVisibleToPackages();
+    method @IntRange(from=1) public int getVersion();
+    method public boolean isForceOverride();
+  }
+
+  public static final class SetSchemaRequest.Builder {
+    ctor public SetSchemaRequest.Builder();
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchemas(@NonNull android.app.appsearch.AppSearchSchema...);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchemas(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
+    method @NonNull public android.app.appsearch.SetSchemaRequest build();
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrator(@NonNull String, @NonNull android.app.appsearch.Migrator);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setMigrators(@NonNull java.util.Map<java.lang.String,android.app.appsearch.Migrator>);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeDisplayedBySystem(@NonNull String, boolean);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setSchemaTypeVisibilityForPackage(@NonNull String, boolean, @NonNull android.app.appsearch.PackageIdentifier);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setVersion(@IntRange(from=1) int);
+  }
+
+  public class SetSchemaResponse {
+    method @NonNull public java.util.Set<java.lang.String> getDeletedTypes();
+    method @NonNull public java.util.Set<java.lang.String> getIncompatibleTypes();
+    method @NonNull public java.util.Set<java.lang.String> getMigratedTypes();
+    method @NonNull public java.util.List<android.app.appsearch.SetSchemaResponse.MigrationFailure> getMigrationFailures();
+  }
+
+  public static final class SetSchemaResponse.Builder {
+    ctor public SetSchemaResponse.Builder();
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addDeletedType(@NonNull String);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addDeletedTypes(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addIncompatibleType(@NonNull String);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addIncompatibleTypes(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addMigratedType(@NonNull String);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addMigratedTypes(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addMigrationFailure(@NonNull android.app.appsearch.SetSchemaResponse.MigrationFailure);
+    method @NonNull public android.app.appsearch.SetSchemaResponse.Builder addMigrationFailures(@NonNull java.util.Collection<android.app.appsearch.SetSchemaResponse.MigrationFailure>);
+    method @NonNull public android.app.appsearch.SetSchemaResponse build();
+  }
+
+  public static class SetSchemaResponse.MigrationFailure {
+    ctor public SetSchemaResponse.MigrationFailure(@NonNull String, @NonNull String, @NonNull String, @NonNull android.app.appsearch.AppSearchResult<?>);
+    method @NonNull public android.app.appsearch.AppSearchResult<java.lang.Void> getAppSearchResult();
+    method @NonNull public String getDocumentId();
+    method @NonNull public String getNamespace();
+    method @NonNull public String getSchemaType();
+  }
+
+  public class StorageInfo {
+    method public int getAliveDocumentsCount();
+    method public int getAliveNamespacesCount();
+    method public long getSizeBytes();
+  }
+
+  public static final class StorageInfo.Builder {
+    ctor public StorageInfo.Builder();
+    method @NonNull public android.app.appsearch.StorageInfo build();
+    method @NonNull public android.app.appsearch.StorageInfo.Builder setAliveDocumentsCount(int);
+    method @NonNull public android.app.appsearch.StorageInfo.Builder setAliveNamespacesCount(int);
+    method @NonNull public android.app.appsearch.StorageInfo.Builder setSizeBytes(long);
+  }
+
+}
+
+package android.app.appsearch.exceptions {
+
+  public class AppSearchException extends java.lang.Exception {
+    ctor public AppSearchException(int);
+    ctor public AppSearchException(int, @Nullable String);
+    ctor public AppSearchException(int, @Nullable String, @Nullable Throwable);
+    method public int getResultCode();
+    method @NonNull public <T> android.app.appsearch.AppSearchResult<T> toAppSearchResult();
+  }
+
+}
+
diff --git a/wifi/api/module-lib-current.txt b/apex/appsearch/framework/api/module-lib-current.txt
similarity index 100%
copy from wifi/api/module-lib-current.txt
copy to apex/appsearch/framework/api/module-lib-current.txt
diff --git a/apex/statsd/framework/api/module-lib-removed.txt b/apex/appsearch/framework/api/module-lib-removed.txt
similarity index 100%
rename from apex/statsd/framework/api/module-lib-removed.txt
rename to apex/appsearch/framework/api/module-lib-removed.txt
diff --git a/apex/statsd/framework/api/removed.txt b/apex/appsearch/framework/api/removed.txt
similarity index 100%
rename from apex/statsd/framework/api/removed.txt
rename to apex/appsearch/framework/api/removed.txt
diff --git a/apex/appsearch/framework/api/system-current.txt b/apex/appsearch/framework/api/system-current.txt
new file mode 100644
index 0000000..4a6194e
--- /dev/null
+++ b/apex/appsearch/framework/api/system-current.txt
@@ -0,0 +1,9 @@
+// Signature format: 2.0
+package android.app.appsearch {
+
+  public class AppSearchManagerFrameworkInitializer {
+    method public static void initialize();
+  }
+
+}
+
diff --git a/apex/statsd/framework/api/system-removed.txt b/apex/appsearch/framework/api/system-removed.txt
similarity index 100%
rename from apex/statsd/framework/api/system-removed.txt
rename to apex/appsearch/framework/api/system-removed.txt
diff --git a/apex/appsearch/framework/jarjar-rules.txt b/apex/appsearch/framework/jarjar-rules.txt
new file mode 100644
index 0000000..50c3ee4
--- /dev/null
+++ b/apex/appsearch/framework/jarjar-rules.txt
@@ -0,0 +1,6 @@
+# Rename all com.android.internal.util classes to prevent class name collisions
+# between this module and the other versions of the utility classes linked into
+# the framework.
+
+# These must be kept in sync with the sources of framework-utils-appsearch
+rule com.android.internal.util.Preconditions* android.app.appsearch.internal.util.Preconditions@1
diff --git a/apex/appsearch/framework/java/TEST_MAPPING b/apex/appsearch/framework/java/TEST_MAPPING
new file mode 100644
index 0000000..12188f8
--- /dev/null
+++ b/apex/appsearch/framework/java/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch"
+    }
+  ]
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
new file mode 100644
index 0000000..fb1cccf
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2020 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.appsearch;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.content.Context;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Provides access to the centralized AppSearch index maintained by the system.
+ *
+ * <p>AppSearch is an offline, on-device search library for managing structured data featuring:
+ *
+ * <ul>
+ *   <li>APIs to index and retrieve data via full-text search.
+ *   <li>An API for applications to explicitly grant read-access permission of their data to other
+ *   applications.
+ *   <b>See: {@link SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage}</b>
+ *   <li>An API for applications to opt into or out of having their data displayed on System UI
+ *   surfaces by the System-designated global querier.
+ *   <b>See: {@link SetSchemaRequest.Builder#setSchemaTypeDisplayedBySystem}</b>
+ * </ul>
+ *
+ * <p>Applications create a database by opening an {@link AppSearchSession}.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
+ *
+ * AppSearchManager.SearchContext searchContext = new AppSearchManager.SearchContext.Builder().
+ *    setDatabaseName(dbName).build());
+ * appSearchManager.createSearchSession(searchContext, mExecutor, appSearchSessionResult -&gt; {
+ *      mAppSearchSession = appSearchSessionResult.getResultValue();
+ * });</pre>
+ *
+ * <p>After opening the session, a schema must be set in order to define the organizational
+ * structure of data. The schema is set by calling {@link AppSearchSession#setSchema}. The schema is
+ * composed of a collection of {@link AppSearchSchema} objects, each of which defines a unique type
+ * of data.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * AppSearchSchema emailSchemaType = new AppSearchSchema.Builder("Email")
+ *     .addProperty(new StringPropertyConfig.Builder("subject")
+ *        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ *        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ *        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ *    .build()
+ * ).build();
+ *
+ * SetSchemaRequest request = new SetSchemaRequest.Builder().addSchema(emailSchemaType).build();
+ * mAppSearchSession.set(request, mExecutor, appSearchResult -&gt; {
+ *      if (appSearchResult.isSuccess()) {
+ *           //Schema has been successfully set.
+ *      }
+ * });</pre>
+ *
+ * <p>The basic unit of data in AppSearch is represented as a {@link GenericDocument} object,
+ * containing an ID, namespace, time-to-live, score, and properties. A namespace organizes a logical
+ * group of documents. For example, a namespace can be created to group documents on a per-account
+ * basis. An ID identifies a single document within a namespace. The combination of namespace and ID
+ * uniquely identifies a {@link GenericDocument} in the database.
+ *
+ * <p>Once the schema has been set, {@link GenericDocument} objects can be put into the database and
+ * indexed by calling {@link AppSearchSession#put}.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * // Although for this example we use GenericDocument directly, we recommend extending
+ * // GenericDocument to create specific types (i.e. Email) with specific setters/getters.
+ * GenericDocument email = new GenericDocument.Builder<>(NAMESPACE, ID, EMAIL_SCHEMA_TYPE)
+ *     .setPropertyString(“subject”, EMAIL_SUBJECT)
+ *     .setScore(EMAIL_SCORE)
+ *     .build();
+ *
+ * PutDocumentsRequest request = new PutDocumentsRequest.Builder().addGenericDocuments(email)
+ *     .build();
+ * mAppSearchSession.put(request, mExecutor, appSearchBatchResult -&gt; {
+ *      if (appSearchBatchResult.isSuccess()) {
+ *           //All documents have been successfully indexed.
+ *      }
+ * });</pre>
+ *
+ * <p>Searching within the database is done by calling {@link AppSearchSession#search} and providing
+ * the query string to search for, as well as a {@link SearchSpec}.
+ *
+ * <p>Alternatively, {@link AppSearchSession#getByDocumentId} can be called to retrieve documents by
+ * namespace and ID.
+ *
+ * <p>Document removal is done either by time-to-live expiration, or explicitly calling a remove
+ * operation. Remove operations can be done by namespace and ID via {@link
+ * AppSearchSession#remove(RemoveByDocumentIdRequest, Executor, BatchResultCallback)}, or by query
+ * via {@link AppSearchSession#remove(String, SearchSpec, Executor, Consumer)}.
+ */
+@SystemService(Context.APP_SEARCH_SERVICE)
+public class AppSearchManager {
+
+    private final IAppSearchManager mService;
+    private final Context mContext;
+
+    /** @hide */
+    public AppSearchManager(@NonNull Context context, @NonNull IAppSearchManager service) {
+        mContext = Objects.requireNonNull(context);
+        mService = Objects.requireNonNull(service);
+    }
+
+    /** Contains information about how to create the search session. */
+    public static final class SearchContext {
+        final String mDatabaseName;
+
+        SearchContext(@NonNull String databaseName) {
+            mDatabaseName = Objects.requireNonNull(databaseName);
+        }
+
+        /**
+         * Returns the name of the database to create or open.
+         *
+         * <p>Databases with different names are fully separate with distinct types, namespaces, and
+         * data.
+         */
+        @NonNull
+        public String getDatabaseName() {
+            return mDatabaseName;
+        }
+
+        /** Builder for {@link SearchContext} objects. */
+        public static final class Builder {
+            private final String mDatabaseName;
+            private boolean mBuilt = false;
+
+            /**
+             * Creates a new {@link SearchContext.Builder}.
+             *
+             * <p>{@link AppSearchSession} will create or open a database under the given name.
+             *
+             * <p>Databases with different names are fully separate with distinct types, namespaces,
+             * and data.
+             *
+             * <p>Database name cannot contain {@code '/'}.
+             *
+             * @param databaseName The name of the database.
+             * @throws IllegalArgumentException if the databaseName contains {@code '/'}.
+             */
+            public Builder(@NonNull String databaseName) {
+                Objects.requireNonNull(databaseName);
+                Preconditions.checkArgument(
+                        !databaseName.contains("/"), "Database name cannot contain '/'");
+                mDatabaseName = databaseName;
+            }
+
+            /** Builds a {@link SearchContext} instance. */
+            @NonNull
+            public SearchContext build() {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                mBuilt = true;
+                return new SearchContext(mDatabaseName);
+            }
+        }
+    }
+
+    /**
+     * Creates a new {@link AppSearchSession}.
+     *
+     * <p>This process requires an AppSearch native indexing file system. If it's not created, the
+     * initialization process will create one under the user's credential encrypted directory.
+     *
+     * @param searchContext The {@link SearchContext} contains all information to create a new
+     *     {@link AppSearchSession}
+     * @param executor Executor on which to invoke the callback.
+     * @param callback The {@link AppSearchResult}&lt;{@link AppSearchSession}&gt; of performing
+     *     this operation. Or a {@link AppSearchResult} with failure reason code and error
+     *     information.
+     */
+    @UserHandleAware
+    public void createSearchSession(
+            @NonNull SearchContext searchContext,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        Objects.requireNonNull(searchContext);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        AppSearchSession.createSearchSession(
+                searchContext,
+                mService,
+                mContext.getUser(),
+                getPackageName(),
+                executor,
+                callback);
+    }
+
+    /**
+     * Creates a new {@link GlobalSearchSession}.
+     *
+     * <p>This process requires an AppSearch native indexing file system. If it's not created, the
+     * initialization process will create one under the user's credential encrypted directory.
+     *
+     * @param executor Executor on which to invoke the callback.
+     * @param callback The {@link AppSearchResult}&lt;{@link GlobalSearchSession}&gt; of performing
+     *     this operation. Or a {@link AppSearchResult} with failure reason code and error
+     *     information.
+     */
+    @UserHandleAware
+    public void createGlobalSearchSession(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        GlobalSearchSession.createGlobalSearchSession(
+                mService, mContext.getUser(), getPackageName(), executor, callback);
+    }
+
+    /** Returns the package name that should be used for uid verification. */
+    @NonNull
+    private String getPackageName() {
+        return mContext.getOpPackageName();
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
new file mode 100644
index 0000000..7dc527a
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.content.Context;
+
+/**
+ * Class holding initialization code for the AppSearch module.
+ *
+ * @hide
+ */
+@SystemApi
+public class AppSearchManagerFrameworkInitializer {
+    private AppSearchManagerFrameworkInitializer() {}
+
+    /**
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers all AppSearch
+     * services to {@link Context}, so that {@link Context#getSystemService} can return them.
+     *
+     * @throws IllegalStateException if this is called from anywhere besides
+     *     {@link SystemServiceRegistry}
+     */
+    public static void initialize() {
+        SystemServiceRegistry.registerContextAwareService(
+                Context.APP_SEARCH_SERVICE, AppSearchManager.class,
+                (context, service) ->
+                        new AppSearchManager(context, IAppSearchManager.Stub.asInterface(service)));
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
new file mode 100644
index 0000000..c738504
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2021 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.appsearch;
+
+import static android.app.appsearch.AppSearchResult.RESULT_INVALID_SCHEMA;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * The helper class for {@link AppSearchSchema} migration.
+ *
+ * <p>It will query and migrate {@link GenericDocument} in given type to a new version.
+ * @hide
+ */
+public class AppSearchMigrationHelper implements Closeable {
+    private final IAppSearchManager mService;
+    private final String mPackageName;
+    private final String mDatabaseName;
+    private final UserHandle mUserHandle;
+    private final File mMigratedFile;
+    private final Set<String> mDestinationTypes;
+    private boolean mAreDocumentsMigrated = false;
+
+    AppSearchMigrationHelper(@NonNull IAppSearchManager service,
+            @NonNull UserHandle userHandle,
+            @NonNull String packageName,
+            @NonNull String databaseName,
+            @NonNull Set<AppSearchSchema> newSchemas) throws IOException {
+        mService = Objects.requireNonNull(service);
+        mUserHandle = Objects.requireNonNull(userHandle);
+        mPackageName = Objects.requireNonNull(packageName);
+        mDatabaseName = Objects.requireNonNull(databaseName);
+        mMigratedFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null);
+        mDestinationTypes = new ArraySet<>(newSchemas.size());
+        for (AppSearchSchema newSchema : newSchemas) {
+            mDestinationTypes.add(newSchema.getSchemaType());
+        }
+    }
+
+    /**
+     * Queries all documents that need to be migrated to a different version and transform
+     * documents to that version by passing them to the provided {@link Migrator}.
+     *
+     * <p>The method will be executed on the executor provided to
+     * {@link AppSearchSession#setSchema}.
+     *
+     * @param schemaType The schema type that needs to be updated and whose {@link GenericDocument}
+     *                   need to be migrated.
+     * @param migrator The {@link Migrator} that will upgrade or downgrade a {@link
+     *     GenericDocument} to new version.
+     */
+    @WorkerThread
+    public void queryAndTransform(@NonNull String schemaType, @NonNull Migrator migrator,
+            int currentVersion, int finalVersion)
+            throws IOException, AppSearchException, InterruptedException, ExecutionException {
+        File queryFile = File.createTempFile(/*prefix=*/"appsearch", /*suffix=*/null);
+        try (ParcelFileDescriptor fileDescriptor =
+                     ParcelFileDescriptor.open(queryFile, MODE_WRITE_ONLY)) {
+            CompletableFuture<AppSearchResult<Void>> future = new CompletableFuture<>();
+            mService.writeQueryResultsToFile(mPackageName, mDatabaseName,
+                    fileDescriptor,
+                    /*queryExpression=*/ "",
+                    new SearchSpec.Builder()
+                            .addFilterSchemas(schemaType)
+                            .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                            .build().getBundle(),
+                    mUserHandle,
+                    new IAppSearchResultCallback.Stub() {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            future.complete(resultParcel.getResult());
+                        }
+                    });
+            AppSearchResult<Void> result = future.get();
+            if (!result.isSuccess()) {
+                throw new AppSearchException(result.getResultCode(), result.getErrorMessage());
+            }
+            readAndTransform(queryFile, migrator, currentVersion, finalVersion);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } finally {
+            queryFile.delete();
+        }
+    }
+
+    /**
+     * Puts all {@link GenericDocument} migrated from the previous call to
+     * {@link #queryAndTransform} into AppSearch.
+     *
+     * <p> This method should be only called once.
+     *
+     * @param responseBuilder a SetSchemaResponse builder whose result will be returned by this
+     *                        function with any
+     *                        {@link android.app.appsearch.SetSchemaResponse.MigrationFailure}
+     *                        added in.
+     * @return the {@link SetSchemaResponse} for {@link AppSearchSession#setSchema} call.
+     */
+    @NonNull
+    AppSearchResult<SetSchemaResponse> putMigratedDocuments(
+            @NonNull SetSchemaResponse.Builder responseBuilder) {
+        if (!mAreDocumentsMigrated) {
+            return AppSearchResult.newSuccessfulResult(responseBuilder.build());
+        }
+        try (ParcelFileDescriptor fileDescriptor =
+                     ParcelFileDescriptor.open(mMigratedFile, MODE_READ_ONLY)) {
+            CompletableFuture<AppSearchResult<List<Bundle>>> future = new CompletableFuture<>();
+            mService.putDocumentsFromFile(mPackageName, mDatabaseName, fileDescriptor, mUserHandle,
+                    new IAppSearchResultCallback.Stub() {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            future.complete(resultParcel.getResult());
+                        }
+                    });
+            AppSearchResult<List<Bundle>> result = future.get();
+            if (!result.isSuccess()) {
+                return AppSearchResult.newFailedResult(result);
+            }
+            List<Bundle> migratedFailureBundles = result.getResultValue();
+            for (int i = 0; i < migratedFailureBundles.size(); i++) {
+                responseBuilder.addMigrationFailure(
+                        new SetSchemaResponse.MigrationFailure(migratedFailureBundles.get(i)));
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (Throwable t) {
+            return AppSearchResult.throwableToFailedResult(t);
+        } finally {
+            mMigratedFile.delete();
+        }
+        return AppSearchResult.newSuccessfulResult(responseBuilder.build());
+    }
+
+    /**
+     * Reads all saved {@link GenericDocument}s from the given {@link File}.
+     *
+     * <p>Transforms those {@link GenericDocument}s to the final version.
+     *
+     * <p>Save migrated {@link GenericDocument}s to the {@link #mMigratedFile}.
+     */
+    private void readAndTransform(@NonNull File file, @NonNull Migrator migrator,
+            int currentVersion, int finalVersion)
+            throws IOException, AppSearchException {
+        try (DataInputStream inputStream = new DataInputStream(new FileInputStream(file));
+             DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(
+                     mMigratedFile, /*append=*/ true))) {
+            GenericDocument document;
+            while (true) {
+                try {
+                    document = readDocumentFromInputStream(inputStream);
+                } catch (EOFException e) {
+                    break;
+                    // Nothing wrong. We just finished reading.
+                }
+
+                GenericDocument newDocument;
+                if (currentVersion < finalVersion) {
+                    newDocument = migrator.onUpgrade(currentVersion, finalVersion, document);
+                } else {
+                    // currentVersion == finalVersion case won't trigger migration and get here.
+                    newDocument = migrator.onDowngrade(currentVersion, finalVersion, document);
+                }
+
+                if (!mDestinationTypes.contains(newDocument.getSchemaType())) {
+                    // we exit before the new schema has been set to AppSearch. So no
+                    // observable changes will be applied to stored schemas and documents.
+                    // And the temp file will be deleted at close(), which will be triggered at
+                    // the end of try-with-resources block of SearchSessionImpl.
+                    throw new AppSearchException(
+                            RESULT_INVALID_SCHEMA,
+                            "Receive a migrated document with schema type: "
+                                    + newDocument.getSchemaType()
+                                    + ". But the schema types doesn't exist in the request");
+                }
+                writeBundleToOutputStream(outputStream, newDocument.getBundle());
+            }
+            mAreDocumentsMigrated = true;
+        }
+    }
+
+    /**
+     * Reads the {@link Bundle} of a {@link GenericDocument} from given {@link DataInputStream}.
+     *
+     * @param inputStream The inputStream to read from
+     *
+     * @throws IOException        on read failure.
+     * @throws EOFException       if {@link java.io.InputStream} reaches the end.
+     */
+    @NonNull
+    public static GenericDocument readDocumentFromInputStream(
+            @NonNull DataInputStream inputStream) throws IOException {
+        int length = inputStream.readInt();
+        if (length == 0) {
+            throw new EOFException();
+        }
+        byte[] serializedMessage = new byte[length];
+        inputStream.read(serializedMessage);
+
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.unmarshall(serializedMessage, 0, serializedMessage.length);
+            parcel.setDataPosition(0);
+            Bundle bundle = parcel.readBundle();
+            return new GenericDocument(bundle);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    /**
+     * Serializes a {@link Bundle} and writes into the given {@link DataOutputStream}.
+     */
+    public static void writeBundleToOutputStream(
+            @NonNull DataOutputStream outputStream, @NonNull Bundle bundle)
+            throws IOException {
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.writeBundle(bundle);
+            byte[] serializedMessage = parcel.marshall();
+            outputStream.writeInt(serializedMessage.length);
+            outputStream.write(serializedMessage);
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        mMigratedFile.delete();
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
new file mode 100644
index 0000000..82b6d62
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -0,0 +1,885 @@
+/*
+ * Copyright 2020 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.appsearch;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.app.appsearch.aidl.AppSearchBatchResultParcel;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.app.appsearch.util.SchemaMigrationUtil;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Provides a connection to a single AppSearch database.
+ *
+ * <p>An {@link AppSearchSession} instance provides access to database operations such as
+ * setting a schema, adding documents, and searching.
+ *
+ * <p>This class is thread safe.
+ *
+ * @see GlobalSearchSession
+ */
+public final class AppSearchSession implements Closeable {
+    private static final String TAG = "AppSearchSession";
+
+    private final String mPackageName;
+    private final String mDatabaseName;
+    private final UserHandle mUserHandle;
+    private final IAppSearchManager mService;
+
+    private boolean mIsMutated = false;
+    private boolean mIsClosed = false;
+
+    /**
+     * Creates a search session for the client, defined by the {@code userHandle} and
+     * {@code packageName}.
+     */
+    static void createSearchSession(
+            @NonNull AppSearchManager.SearchContext searchContext,
+            @NonNull IAppSearchManager service,
+            @NonNull UserHandle userHandle,
+            @NonNull String packageName,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        AppSearchSession searchSession =
+                new AppSearchSession(service, userHandle, packageName, searchContext.mDatabaseName);
+        searchSession.initialize(executor, callback);
+    }
+
+    // NOTE: No instance of this class should be created or returned except via initialize().
+    // Once the callback.accept has been called here, the class is ready to use.
+    private void initialize(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
+        try {
+            mService.initialize(
+                    mPackageName,
+                    mUserHandle,
+                    /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
+                    new IAppSearchResultCallback.Stub() {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> {
+                                AppSearchResult<Void> result = resultParcel.getResult();
+                                if (result.isSuccess()) {
+                                    callback.accept(
+                                            AppSearchResult.newSuccessfulResult(
+                                                    AppSearchSession.this));
+                                } else {
+                                    callback.accept(AppSearchResult.newFailedResult(result));
+                                }
+                    });
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private AppSearchSession(@NonNull IAppSearchManager service, @NonNull UserHandle userHandle,
+            @NonNull String packageName, @NonNull String databaseName) {
+        mService = service;
+        mUserHandle = userHandle;
+        mPackageName = packageName;
+        mDatabaseName = databaseName;
+    }
+
+    /**
+     * Sets the schema that represents the organizational structure of data within the AppSearch
+     * database.
+     *
+     * <p>Upon creating an {@link AppSearchSession}, {@link #setSchema} should be called. If the
+     * schema needs to be updated, or it has not been previously set, then the provided schema will
+     * be saved and persisted to disk. Otherwise, {@link #setSchema} is handled efficiently as a
+     * no-op call.
+     *
+     * @param request the schema to set or update the AppSearch database to.
+     * @param workExecutor Executor on which to schedule heavy client-side background work such as
+     *                     transforming documents.
+     * @param callbackExecutor Executor on which to invoke the callback.
+     * @param callback Callback to receive errors resulting from setting the schema. If the
+     *                 operation succeeds, the callback will be invoked with {@code null}.
+     */
+    public void setSchema(
+            @NonNull SetSchemaRequest request,
+            @NonNull Executor workExecutor,
+            @NonNull @CallbackExecutor Executor callbackExecutor,
+            @NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
+        Objects.requireNonNull(request);
+        Objects.requireNonNull(workExecutor);
+        Objects.requireNonNull(callbackExecutor);
+        Objects.requireNonNull(callback);
+        Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+        List<Bundle> schemaBundles = new ArrayList<>(request.getSchemas().size());
+        for (AppSearchSchema schema : request.getSchemas()) {
+            schemaBundles.add(schema.getBundle());
+        }
+        Map<String, List<Bundle>> schemasVisibleToPackagesBundles =
+                new ArrayMap<>(request.getSchemasVisibleToPackagesInternal().size());
+        for (Map.Entry<String, Set<PackageIdentifier>> entry :
+                request.getSchemasVisibleToPackagesInternal().entrySet()) {
+            List<Bundle> packageIdentifierBundles = new ArrayList<>(entry.getValue().size());
+            for (PackageIdentifier packageIdentifier : entry.getValue()) {
+                packageIdentifierBundles.add(packageIdentifier.getBundle());
+            }
+            schemasVisibleToPackagesBundles.put(entry.getKey(), packageIdentifierBundles);
+        }
+
+        // No need to trigger migration if user never set migrator
+        if (request.getMigrators().isEmpty()) {
+            setSchemaNoMigrations(
+                    request,
+                    schemaBundles,
+                    schemasVisibleToPackagesBundles,
+                    callbackExecutor,
+                    callback);
+        } else {
+            setSchemaWithMigrations(
+                    request,
+                    schemaBundles,
+                    schemasVisibleToPackagesBundles,
+                    workExecutor,
+                    callbackExecutor,
+                    callback);
+        }
+        mIsMutated = true;
+    }
+
+    /**
+     * Retrieves the schema most recently successfully provided to {@link #setSchema}.
+     *
+     * @param executor Executor on which to invoke the callback.
+     * @param callback Callback to receive the pending results of schema.
+     */
+    public void getSchema(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<AppSearchResult<GetSchemaResponse>> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        Preconditions.checkState(!mIsClosed, "AppSearchSession has already been closed");
+        try {
+            mService.getSchema(
+                    mPackageName,
+                    mDatabaseName,
+                    mUserHandle,
+                    new IAppSearchResultCallback.Stub() {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> {
+                                AppSearchResult<Bundle> result = resultParcel.getResult();
+                                if (result.isSuccess()) {
+                                    GetSchemaResponse response =
+                                            new GetSchemaResponse(result.getResultValue());
+                                    callback.accept(AppSearchResult.newSuccessfulResult(response));
+                                } else {
+                                    callback.accept(AppSearchResult.newFailedResult(result));
+                                }
+                            });
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieves the set of all namespaces in the current database with at least one document.
+     *